Archive for February, 2010

PowerShell Script Export-ADGroupToHTML.ps1

Project Objective:
Make one place and one place only a repository for employee contact information.

Problem to be solved:
Curently there are two places people retrieve contact information. Static web page made from an Excel spreadsheet everyone has Full access to and of course the second Outlook (Exchange/Active Directory).

Suggestions:
Sync the web page with the information in Active Directory – REJECTED (Security risk: tamper accidental or otherwise could occur with other people’s information.
Accepted Solution – Allow users to change their own information in Active Directory with GALMod32, export contact information to a formated html file that uses the site’s CSS and Sortable Table to allow viewers to sort the contact information anyway they see fit.

Future Versions:
This code needs to be rewritten with proper procedures instead of a single massive pipe. I would also like to be able to add a Manager collum however in its current form (one large pipe) that isn’t easy as the Manager field resolves to a DN and resolving that DN inline while preservig the object being piped isn’t trivial. That’s what happens when you write a massive pipe. LOL

# Export-ADgroupToHTML.ps1
#
# Written by Aaron Wurthmann (aaron <AT> wurthmann <DOT> com)
#    co-written by Tobias Speckbacher
#
# If you edit please keep my name as an original author and
# keep me apprised of the changes, see email address above.
# This code may not be used for commercial purposes.
# You the executor,runner,user accept all liability.
# This code comes with ABSOLUTELY NO WARRANTY.
# You may redistribute copies of the code under the terms of the GPL v2.
# -----------------------------------------------------------------------
# Prerequisite:
# Written for PowerShell v2
# Quest ActiveRoles Management Shell for Active Directory Plugin Required
#     http://www.quest.com/powershell/activeroles-server.aspx
# -----------------------------------------------------------------------
# 2010.02.01 ver 2.1
#
# Summary:
# Enumerates an Active Directory Group then Exports group members'
# contact information into a formatted HTML file. Checks to see if there
# will be more than a 10% change to the file. If there will be, abort.
# I built this feature in mostly as a proof of concept for another script
# but to basically insure that for some freakish reason the file doesn't
# get blanked out or all the records removed.
#
# Notes:
# This was/is my first PowerShell script and what won me over
# to using PowerShell. The script does need a re-write with everything
# I have learned and some functions I plan on returning to this script and
# re-writting it someday. For the most part PowerShell is new to me so as
# such the "main" function is a series of pipes. One thing you will need
# to watch out for, since the main is a series of pipes, is memory usage.
# After running this script a few times in a single shell I noticed
# powershell.exe was using more and more memory. While testing and
# tweaking you may need to exit your shell and restart a new one.
# I dont "think" this is a problem if the script is running as a
# Scheduled Task, just when its run over and over in your shell.
#************************************************************************

#Edit Varibles Here, File Paths and Names, DN for All users group, CSS Style
$temphtml="C:inetpubwwwrootwssVirtualDirectories80contacttemp.htm"
$finalhtm="C:inetpubwwwrootwssVirtualDirectories80contactdata.htm"

$allGroup="CN=Domain Users,OU=Users,DC=company,DC=ext"
$properties='Name', 'Title', 'telephoneNumber', 'mobile', 'HomePhone', 'facsimileTelephoneNumber','Notes'

$head='
    <meta name="GENERATOR" content="Microsoft SharePoint" />
    <meta name="progid" content="SharePoint.WebPartPage.Document" />
    <meta HTTP-EQUIV="Content-Type" content="text/html; charset=utf-8" />
    <meta HTTP-EQUIV="Expires" content="0" /><META NAME="ROBOTS" CONTENT="NOHTMLINDEX"/>
    <script type="text/javascript" src="sortable.js"></script>
    <title>Company Contact List</title>
    <link rel="stylesheet" type="text/css" href="_layouts/1033/styles/core.css?rev=5msmprmeONfN6lJ3wtbAlA%3D%3D"/>
    <link rel="stylesheet" type="text/css" id="onetidThemeCSS" href="_themes/Cardinal/Card1011-65001.css?rev=12%2E0%2E0%2E6421"/>
    <script type="text/javascript" language="javascript" src="_layouts/1033/init.js?rev=qX%2BG3yl4pldKy9KbPLXf9w%3D%3D"></script>
    <script type="text/javascript" language="javascript" src="_layouts/1033/core.js?rev=CNBZRdV1h3pKuA7LsMXf3w%3D%3D" defer></script>
    <script type="text/javascript" language="javascript" src="_layouts/1033/ie55up.js?rev=Ni7%2Fj2ZV%2FzCvd09XYSSWvA%3D%3D"></script>
    <link type="text/xml" rel="alternate" href="_vti_bin/spdisco.aspx" />
    <META Name="CollaborationServer" Content="SharePoint Team Web Site">
    <style type="text/css">
        a img {border: 0;}
        table.sortable {border-width:4px; border-style:hidden; border-color:none; border-collapse:collapse; width:150%;}
        table.sortable th, table.sortable td {font-size:1em; text-align: left; padding: 4px; border-style: solid; border-color:none;}
        table.sortable th {border-width: 0px 0px 3px 0px;background-color: #ccc;}
        table.sortable td {font-size:0.9em; border-width:0px 0px 0px 0px; border-color:#444}
        table.sortable tr.odd td {background-color: #ddd;}
        table.sortable tr.even td {background-color: #fff;}
        table.sortable tr.sortbottom td {border-top: 1px solid #444;background-color: #ccc;font-weight: bold;}
    </style>'
#End Editable Area

#region Main: If not present add PSSnapin Quest.ActiveRoles.ADManagement, Enumerate Users in All group, Select Desired Properties,...
# ...Sort by Name, Output as temporary HTML file with above header, Replace Table Header with formated one
# The line below is expected to error then recover, I dont know how to properly check then add Snapins yet
if (Get-PSSnapin -name Quest.ActiveRoles.ADManagement) {} else {Add-PSSnapin Quest.ActiveRoles.ADManagement}

Get-QADGroupMember $allGroup -Indirect |
where {$_.Type -eq ("User")} |
Get-QADUser |
Select-Object -property $properties |
Sort-Object -Property 'Name' |
ConvertTo-Html -head $head |
Foreach-Object {$_ -creplace '<table>','<table class="sortable" id="employees">'} |
Foreach-Object {$_ -creplace '<tr><th>Name</th><th>Title</th><th>telephoneNumber</th><th>mobile</th><th>HomePhone</th><th>facsimileTelephoneNumber</th><th>Notes</th></tr>','<tr><th>Name</th><th>Title</th><th>Office              </th><th>Mobile              </th><th>Home               </th><th>Fax                </th><th>Notes</th></tr>'} |
Out-File $temphtml
#endregion

# Create New Data.htm IF Data.htm already exists and If temporary HTML file is between 10% smaller or 10% larger
if (test-path $finalhtm) {
    $tempfileSize=Get-ChildItem $temphtml | ForEach-Object {($_.Length)}
    $finalhtmSize=Get-ChildItem $finalhtm | ForEach-Object {($_.Length)}
    $fileDiff=($finalhtmSize/$tempfileSize)
    if ($fileDiff -gt 0.9) {
        if ($fileDiff -lt 1.1) {
            Remove-Item $finalhtm
            Rename-Item $temphtml -NewName $finalhtm
            }
        }
    }
#endregion

VisualBasic Script check_eventlogs.wsf

Project Objective:
Create a Nagios addon to be run with NRPE/NSClient++ that checks the Windows event logs for errors.

Problem to be solved:
Increased monitoring of Windows systems. Get notified of any and all errors as they happen opposed to after something worse happens be it hard drive failure, service offline, etc.

Suggestions:
Use existing native Nagios module – REJECED Existing module doesn’t have enough filter capability to prevent IT from being spammed with EVERY single request AND doesnt provide verbose output/what the error even is, just that there was an error.
Accepted Solution: Write our own module to use with a WSF wrapper (as was the norm on NagiosExchange) at the time.

Future Versions:
The original version of this script and another were posted on Nagios Exchange. For whatever reason they are missing now, even though they were quite popular for some time. Future versions will utilize PowerShell over VBS as many of the commands used here are native and faster in PowerShell.

'#***********************************************************************
'# "Check_EventLogs.wsf""
'#
'# "Insipred" by Aaron Wurthmann (aaron (AT) wurthmann (DOT) com)
'#
'#
'# If you edit please keep my name as an original author and
'# keep me apprised of the changes, see email address above.
'# This code may not be used for commercial purposes.
'# You the executor,runner,user accept all liability.
'# This code comes with ABSOLUTELY NO WARRANTY.
'# You may redistribute copies of the code under the terms of the GPL v2.
'# -----------------------------------------------------------------------
'# Notes:
'# The core of this script was re-written by two collegues of mine.
'# I was having problems with my previous attempts at solving this problem
'# So I mailed what I had off to a friend, when it came back it was re-written.
'# Thank you dstenseth and acakir, may the foos gods smile upon thee.
'# For debugging I recomend testing your queries out with wbemtest.
'# I adapted this script from ronald van vugt's Check_Services.wsf
'# -----------------------------------------------------------------------
'# 2007.07.31 ver FINAL
'#
'# Summary:
'# Checks System and Application event logs for Warnings and Errors;
'# If an error(s) are found, send verbose information including error message.
'#************************************************************************

<job>
<runtime>
  <description>

Check_EventLogs (nrpe_nt-plugin) 1.0
This nrpe_nt plugin come with ABSOLUTELY NO WARRANTY. You may redistribute
copies of the plugins under the terms of the GNU General Public License v2.

  </description>
    <named
      name="h"
      helpstring="Help"
      type="simple"
      required="false"
    />
  />

  <example>

  You do not need a string for this plugin.

  This script checks the event logs for Warnings and Errors;
  If an error is found, verbose information is sent back. A
  registry key is written in order to track when the last time
  checked was.

  Usage:
  command [check_eventlogs]=c:Windowssystem32cscript.exe //NoLogo //T:10 check_eventlogs.wsf

  </example>

</runtime>

<script language="VBScript">

'*******************************************************************
' Help
'*******************************************************************
If Wscript.Arguments.Named.Exists("h") Then
      Wscript.Echo "Plugin help screen:"
      Wscript.Arguments.ShowUsage()
      Wscript.Quit(0)
End If

'*******************************************************************
' Main
'*******************************************************************
Dim dtmFrom
Dim errCount
Dim intResultWarning
Dim intResultError
Dim strResultWarning
Dim strResultError
Dim strComputer
Dim oReg

Const AppKey = "SYSTEMCurrentControlSetServicesNRPE_NT"
Const AppVal = "LastExec"
Const CONVERT_TO_LOCAL_TIME = True
Const ForReading = 1
Const ForWriting = 2
Const HKLM = &H80000002

intResultWarning = 0
intResultError = 0
ExecDate_Current = CDate(Now)
strComputer = "."

Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\" & strComputer & "rootdefault:StdRegProv")
oReg.GetStringValue HKLM,AppKey,AppVal,ExecDate_Last 

if IsNull ( ExecDate_Last ) then
        oReg.CreateKey HKLM, AppKey
        ExecDate_Last = CDate(Now)
else
        ExecDate_Last = CDate(ExecDate_Last)
end If

Set dtmFrom = CreateObject("WbemScripting.SWbemDateTime")
dtmFrom.SetVarDate ExecDate_Last, CONVERT_TO_LOCAL_TIME
Set dtmTo = CreateObject("WbemScripting.SWbemDateTime")
dtmTo.SetVarDate ExecDate_Current, CONVERT_TO_LOCAL_TIME

Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & strComputer & "rootcimv2")
query = "SELECT * FROM Win32_NTLogEvent WHERE (Logfile='Application' AND Type<>'Information' AND TimeWritten >='" & dtmFrom & "')_
         or (Logfile='System' AND Type<>'Information' AND TimeWritten >='" & dtmFrom & "') "

Set colEvents = objWMI.ExecQuery(query)
oReg.SetStringValue HKLM,AppKey,AppVal,CStr(Now)
errCount = colEvents.Count

if ( errCount > 0 ) then

        For Each objEvent in colEvents
                if objEvent.Type = "Error" then
                        intResultError = 2
                        if strResultError <> "" then
                                strResultError = _
                                objEvent.Logfile & " Log - Error!! " & vbCRLF &_
                                "Source: " & objEvent.SourceName & vbCRLF &_
                                "Event Code: " & objEvent.EventCode & vbCRLF &_
                                "Message: " & objEvent.Message & " " & vbCRLF &_
                                vbCRLF & strResultError
                        else
                                strResultError = _
                                objEvent.Logfile & " Log - Error!! " & vbCRLF &_
                                "Source: " & objEvent.SourceName & vbCRLF &_
                                "Event Code: " & objEvent.EventCode & vbCRLF &_
                                "Message: " & objEvent.Message & " " & vbCRLF
                        end if
                else
                        if objEvent.Type = "Warning" then
                                intResultWarning = 1
                                if strResultWarning <> "" then
                                        strResultWarning = _
                                        objEvent.Logfile & " Log - Warning! " & vbCRLF &_
                                        "Source: " & objEvent.SourceName & vbCRLF &_
                                        "Event Code: " & objEvent.EventCode & vbCRLF &_
                                        "Message: " & objEvent.Message & " " & vbCRLF &_
                                        vbCRLF & strResultWarning
                                else
                                        strResultWarning = _
                                        objEvent.Logfile & " Log - Warning! " & vbCRLF &_
                                        "Source: " & objEvent.SourceName & vbCRLF &_
                                        "Event Code: " & objEvent.EventCode & vbCRLF &_
                                        "Message: " & objEvent.Message & " " & vbCRLF
                                end if
                        end if
                end if
        next
end if

Select case intResultWarning + intResultError
  Case 0 wscript.echo "No Errors or Warnings found in System or Application Event Logs"
         wscript.quit(0)
  Case 1 wscript.echo strResultWarning
         wscript.quit(1)
  Case 2 wscript.echo strResultError
         wscript.quit(2)
  Case 3 wscript.echo strResultWarning & vbCRLF & strResultError
         wscript.quit(2)
end select

' ----- End of Script -----------------------------------------------------------------

Function WMIDateStringToDate(dtmEventDate)
    WMIDateStringToDate = CDate(Mid(dtmEventDate, 5, 2) & "/" & _
        Mid(dtmEventDate, 7, 2) & "/" & Left(dtmEventDate, 4) _
            & " " & Mid (dtmEventDate, 9, 2) & ":" & _
                Mid(dtmEventDate, 11, 2) & ":" & Mid(dtmEventDate, _
                    13, 2))
End Function
</script>
</job>