Powershell: Create Event with parameters

This function will let you stamp events to the Windows EventLog, and feed the event with filterable parameterdata (which in the cases you use SCOM to sniff events, is pretty awesome).

I use this all the time in cases where a script should dump some kind of result to the eventlog, and using SCOM to fetch the event and trigger on special texts or values in the parameterdata returned.

function createParamEvent ()
  {
    <#
  .SYNOPSIS
  Function for creating events, just like create-event or eventcreate.exe - but with the added functionality to add up to 5 filterable parameters.
    .DESCRIPTION
  The function stamps Windows Events to the Windows Eventlog by your choice, but can also be fed up to 5 different parameters, where param1 contains the basic Event Description, and param2 to param5 contains data of your choosing.
    .EXAMPLE
  For Information events, use eventID 220:
  CreateParamEvent -source "TestSource" -evtID 220 -param1 "The server $hostname shut down at $timestamp" -param2 $hostname -param3 $timestamp -param4 "Some generic text"
  .EXAMPLE
  For Warning events:
  CreateParamEvent -source "TestSource" -evtID 221 -param1 "The server $hostname shut down at $timestamp" -param2 $hostname -param3 $timestamp -param4 "some generic text"
  .EXAMPLE
  For Error events, with the manditory param1 set. All parameters from param2 to param5 are not manditory:
  CreateParamEvent -source "TestSource" -evtID 222 -param1 "The server $hostname shut down at $timestamp"
  .EXAMPLE
  Alle andre eventID'er vil logges som information events.
  .PARAMETER evtID
  Mandatory: The logic in this function is based on the principle where the sample eventIDs (222, 221, 220) will throw an error corresponding to the Event Type (error, warning, information). Other EventIDs can be used, but will then be logged as an Information Event.
  .PARAMETER param1
  Mandatory: The full description in the event.
  .PARAMETER param2-5
  Use theese parameters to add additional useful information to the mix, for example additional information that can be pulled from the Event in SCOM.
  .Link
  https://vetasen.no
  .Notes
  - Param1 = Full description in the event
  - Source is mandetory
  - EventID is mandetory
  - Eventid 222 = Error event
  - Eventid 221 = Warning event
  - Eventid 220 = Information event
  - Param2 to 5 are optional.
  #>
  [Cmdletbinding()]
Param
          (
            [parameter(Mandatory=$true)][string]$evtID,
            [parameter(Mandatory=$true)][string]$param1,
            [parameter(Mandatory=$true)][string]$source,
            [string]$param2,
            [string]$param3,
            [string]$param4,
            [string]$param5
          )
    #Define the event log
    $evtlog = "Application"

    #Load the event source to the log if not already loaded.  This will fail if the event source is already assigned to a different log.
    if ([System.Diagnostics.EventLog]::SourceExists($source) -eq $false) {
        [System.Diagnostics.EventLog]::CreateEventSource($source, $evtlog)
    }

    if ($evtID -eq 222){
    $id = New-Object System.Diagnostics.EventInstance($evtID,1,1); #ERROR EVENT
    }
    elseif ($evtID -eq 221){
    $id = New-Object System.Diagnostics.EventInstance($evtID,1,2); #WARNING EVENT
    }
    else{
    $id = New-Object System.Diagnostics.EventInstance($evtID,1); #INFORMATION EVENT
    }    
    
    
    
    $evtObject = New-Object System.Diagnostics.EventLog;
    $evtObject.Log = $evtlog;
    $evtObject.Source = $source;
    $evtObject.WriteEvent($id, @($param1,$param2,$param3,$param4,$param5))
  }

 

Powershell: Get file- and foldersize for given path

Quick and dirty little thing I use to get the file- and foldersize for any given path.

# Get-pathsize.ps1
# Use: C:scriptsget-pathsize.ps1 -path <your-path>

param (
$path
)

try {
 Get-ChildItem $path -Hidden -ErrorAction Stop
}

catch {
 $_.exception
 break
}

$colItems = (Get-ChildItem $path -recurse | Measure-Object -property length -sum) 
[int]$size = [math]::round($colItems.sum /1MB, 2) 
write-host "Files and foldersize in $path is: $size MB"

-F

SCOM: Command Channel Script

This little script is what I use in cooperation with the SCOM Command Channel to parse and send SCOM alerts to a logfile.
The script will take the SCOM alert parameters and put them neatly in a .log file, one file for each alert I want. This, of course, is customizable – I just like to see the amount of files being generated.

The Channel:

Selection_001

The above channel parameters:

Path: C:\windows\system32\WindowsPowershell\v1.0\powershell.exe
Cmd: -file “C\:Script\AlertExport.ps1” “$Data[Default=’Not Present’]/Context/DataItem/AlertId$##$Data[Default=’Not Present’]/Context/DataItem/AlertName$##$Data[Default=’Not Present’]/Context/DataItem/AlertDescription$##$Data[Default=’Not Present’]/Context/DataItem/EntityPath$##$Data[Default=’Not Present’]/Context/DataItem/EntityDisplayName$”
Startdir: c:\

This will get you the following (of MANY) Alert details: AlertID, Alert Name, Alert Description, Path and Displayname.

The Script:

# Alert Params
param(
$parameters 
)
$params = $parameters.split('##') | ? {$_ -ne ''}

# Build params (added commented blocks of Alert parameter data for your convenience)
$AlertID = $params[0] # $Data/Context/DataItem/AlertID$
$AlertName = $params[1] # $Data/Context/DataItem/AlertName$
$AlertDesc = $params[2]# $Data/Context/DataItem/AlertDescription$
$Path = $params[3] # $Data/Context/DataItem/ManagedEntityPath$
$DisplayName = $params[4] # $Data/Context/DataItem/ManagedEntityDisplayName$


# Sharestuff
$share = "<YOUR SHARE AND STUFF>"
$date = get-date
$Alertfile = "SCOM Alert - $(get-date -Format "dd.MM.yyyy HH.mm.ss").log"

# Format AlertMessage
$AlertMessage = @()

$AlertMessage += "ID: $AlertID"
$AlertMessage += "Date: $date"
$AlertMessage += "DisplayName: $DisplayName"
$AlertMessage += "AlertName: $AlertName"
$alertMessage += "Path: $Path"
$AlertMessage += "Description: $AlertDesc"

# Output alert to textfile
$AlertMessage >> $share$alertfile

Put the script on all your Management Servers, in this case in the C:\script folder, and suddenly, if all goes well, your selected Alerts will start pumping out to this share.

alerts

– F

Query MSSQL with Powershell

I often use different variety of this snippet to do stuff with MSSQL databases (and other types as well, with minor changes to the script).
The script will use SQL Auth by default.
To change this to Windows Auth, change the Connection String to:

$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBname; Integrated Security = True;"

Note: With Windows Auth, the script will run as the current user.

$SQLServer = "YourDBInstance"
$SQLDBname = "DBName"

$SQLUser = "DBuser"
$SQLPwd = "DBpassword"

$SQLQuery = @"

-- insert your query here --

"@

$SqlConnection = New-Object System.Data.SqlClient.SqlConnection 
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBname; Integrated Security = False; User ID=$SQLUser; Password=$SQLPwd;"
  
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand 
$SqlCmd.CommandText = $SQLQuery 
$SqlCmd.Connection = $SqlConnection 
  
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 
$SqlAdapter.SelectCommand = $SqlCmd 
  
$DataSet = New-Object System.Data.DataSet 
$SqlAdapter.Fill($DataSet) 

$SqlConnection.Close() 

$output = $DataSet.Tables[0]

– F

Test webservices with Powershell

I use this little thing to test webservices (by invoking SOAP/GET request etc) whenever I want to parse the output to, say, Windows Event Logs, or the nearest SoapUI installation is far far away.
The $request.SetRequestHeader parameters may vary from situation to situation, but in most cases this code should be sufficient for simple Webservices.
The only thing you need is the Webservice URL, and a set of XML parameters, depending on which test you want to do.

Originally written as a function for a bigger script, but the code should be easy to modify for other stuff.

 
#-- Global Parameters

$global:WebServiceURL = " -- URL to webservice here -- "
$global:XMLParameters = @"

-- Paste you XML request here --

"@

#-- The Actual Function

function CallWebservice {
echo "Sending webrequest to $WebServiceURL"

$request = New-Object -ComObject Msxml2.XMLHTTP
$request.open('POST', $WebServiceURL, $false)
$request.setRequestHeader("Content-type", "text/xml; charset=utf-8")
$request.setRequestHeader("Content-length", $XMLParameters.length)
$request.setRequestHeader("Connection", "close")
$request.send($XMLParameters)
$request.statusText
$request.status
$request.responseText
}

CallWebservice

– F

Output displayname and IP address for SCOMagents

Got bored – wrote this little thing to output FQDN and IPaddress for all Windows and UnixLinux agents in my lab environment.

Could be useful for some people maybe.
 

ipmo operationsmanager
$nixservers = get-scomclass -name "Microsoft.Unix.Computer" | Get-SCOMMonitoringObject
$winservers = Get-SCOMClass -name "Microsoft.Windows.Computer" | Get-SCOMMonitoringObject

   
    Write-host "-----------------------------------------------------------------"
    write-host "-------------------- Unix Computers and IPs ---------------------"
    Write-host "-----------------------------------------------------------------"
foreach ($nix in $nixservers) 

    {
        write-host ([System.Net.Dns]::GetHostAddresses($nix) | foreach {echo $nix - $_.IpAddressToString})
    }


    Write-host "-----------------------------------------------------------------"
    write-host "------------------- Windooze Computers and IPs ------------------"
    Write-host "-----------------------------------------------------------------"
foreach ($win in $winservers) 

    {
        write-host ([System.Net.Dns]::GetHostAddresses($win) | foreach {echo $win - $_.IpAddressToString})
    }

 
Thank god it’s Friday…

-F

Monitor Active/Passive Clustered Services… in SCOM?

I was playing around in Powershell the other day, and made this little thingy to help me monitor clustered Windows Services in an Active/Passive Windows Cluster solution.
The script checks if specific Windows Services are running or not, and determines which node is active in the cluster by using the get-wmiobject cmdlet.

There are many different uses for this, and can easily be modified to for example create events on the server you’re executing the script from.

This is also a really easy way to monitor Clustered Active/Passive services in Operations Manager, which is a REAL pain to do without making some overly complicated Service Monitors.
Why complicated you ask? Clusterservers do not have SCOM Agents installed,only the logical clusternode has agents. Read more about this here.
Alternatively you can do it like the pros do, and add intelligence to the monitors, described here.

Wow that was some sidetrack – enough fufflin’ around! Let’s look at this awesome script!

# Monitor Clustered Windows Services v 1.0
# www.fuffle.net

clear-host
$getcluster = Get-WmiObject win32_computersystem -computername {"ENTER LOGICAL CLUSTERNAME HERE"} | select-object name
$activenode = $getcluster.name
$cluservice = 'BTSSvc$SingleReceiveHost','BTSSvc$SingleReceiveHost32','BTSSvc$SingleSendHost','BTSSvc$SingleSendHost32','BTSSvc$SingleWcfSqlHost','w3svc','Btsaalsvc','ENTSSO','RuleEngineUpdateService'

# Alternativly you can list all servicenames in a file - uncomment line 10 and comment line 7
#$cluservice = get-content "C:tempservicelist.txt"

foreach ($node in $activenode)

{
$service = get-service -computername $activenode $cluservice | Select-Object Status,Name,displayname

# Check all services for state, then write out result
foreach ($s in $service)
    {
    # If services are in a "running" state
    if($service.status -eq "running")
    {write-host "The service" $s.displayname "is running on active clusternode" $getcluster.name"- All is well."}
        # If services are in a "stopped" state
        elseif($service.status -eq "stopped")
        {write-host "The service" $s.displayname "has stopped on active clusternode" $getcluster.name"- Some poo has hit the fan."}
            # If services are in a different state than "Running" or "Stopped"
            else
            {write-host "The service" $s.displayname "is returning with status" $service.status "- Investigate this on " $getcluster.name}
        } 
    } 

Feel free to contact me if you have any questions or remarks about the script. I am a Powershell newbie, and I have no doubt that there is some better way to do this sort of thing.

– F

SCOM: Alert Task – Copy alert to clipboard

In our daily line of work, we sometimes need to show server admins and system managers alerts related to their infrastructure. Have you ever tried to copy/paste the Alert Details for an alert? It looks like crap, and contains alot of information the server admins and system managers couldn’t care less about.

To make this a little easier, we created an Alert Task which copies relevant information in the Alert Details to clipboard, namely Timeraised, PrincipalName, Name and Description.

1. Go to Authoring > Tasks.
2. Click «Create a New Task» in the  Tasks pane to the right.
3.  Choose «Alert Command Line» under the Console Tasks folder.
4. Select a management pack to use, or create a new one.
5. Select a Task name, and type in some description if necessary.

6. Type in the application location and parameters exactly as shown below. (The additional settings is not that important).
pic1

Application:
C:WindowsSystem32WindowsPowerShellv1.0powershell.exe

Parameters:
import-module operationsmanager;Get-scomalert -id $ID$ | fl Timeraised,PrincipalName,Name,Description | clip

7. Click Create, and you are done. Now you will find the Alert Task in the Task pane to the right in the Active Alerts view under Monitoring in the Operations Manager Console.

Sidenote: If you want to create a .txt file with the alert, just replace the pipe and clip (| clip) with >> C:tempalert.txt like so:

import-module operationsmanager;Get-scomalert -id $ID$ | fl Timeraised,PrincipalName,Name,Description >> C:tempalert.txt

-F

Unrar archives with Powershell

Are you like me and have literally thousands of .rar archived material laying around on old disks?

It can be a pain in the lower region of the backside of your body to unrar all of those files without it being time consuming and boring as hell.

After some fiddlin’ around in PowerShell and some Googelin’, I  created this script to do the job for me. It uses unrar.exe, a commande line based extract tool to do the job, and plases the files in a directory of your choice. Just run the script, and it unrars all the archives it finds under the parent folder.

Unrar.exe can be downloaded from here.

Remember to change the directory to unrar.exe if you choose a different install dir.

Please feel free to comment if you have some way of improving or simplifying the code.

– F

(Based on the script of this awesome guy)

$parent = 'c:temprar'
$unrarred = 'c:tempunrar'
$files = @()

# Test to see if Unpackdir is present
if ((Test-Path -Path $unrarred) -ne $true)
 
# If not present, create Unpackdir
{md C:Tempunrar}


Get-ChildItem $parent -Recurse -Filter "*.rar" | % {

    # Recurse through all subfolders looking for .rar files only.

    $files = $files + $_.FullName
}

foreach ($f in $files) {

    # UnRAR the files. -y responds Yes to any queries UnRAR may have.

   C:unrarUnRAR.exe x -y $f $unrarred
}

Powershell Execution Policy

The Set-ExecutionPolicy cmdlet enables you to determine which Windows PowerShell scripts (if any) will be allowed to run on your computer. Windows PowerShell has four different execution policies:

  • Restricted – No scripts can be run. Windows PowerShell can be used only in interactive mode.
  • AllSigned – Only scripts signed by a trusted publisher can be run.
  • RemoteSigned – Downloaded scripts must be signed by a trusted publisher before they can be run.
  • Unrestricted – No restrictions; all Windows PowerShell scripts can be run.

To assign a particular policy simply call Set-ExecutionPolicy followed by the appropriate policy name. For example, this command sets the execution policy to Unrestricted:

Set-ExecutionPolicy Unrestricted