This is a place for Systems Administrators and IT Professionals to find and share ideas, solutions and templates. If you have something that helps you solve a problem, chances are it will help someone else too. So pay it forward and send an email to TheAgreeableCow at gmail. Full mudos to you!

Saturday 8 September 2012

SysAdmin Modular Reporting (SAMReports)

What is it?
The SysAdmin Modular Reporting framework provides a consistent, flexible data collection and reporting tool with 'traffic light' style alerts for your environment. Written in Powershell using an easy to follow style, the frameworks collates any number of user generated plugins (function scripts), into a single report for any Windows system supporting Powershell.

For a full overview of the framework and information to help create your own scripts

Please see the Quick Start Guide (pdf)

Here's a quick extract from the Veeam report (see full example below).

Download Latest Version
The reporting framework consists of the Core Components and a collection of separate Modules which contain the individual functions that combine to create a final report.

View the scripts on GitHub
*I encourage you to review and understand any script downloaded from the internet. Also ensure to "unblock" each .ps1 files (Right click | Properties | Unblock), to avoid the [D] Do not run [R] Run once [S] Suspend security prompts.

Please note; this is very much a community sourced project. Please send any suggestions, ideas or plugins to

Core Components
There is one parent script called Get-SAMReport.ps1, which is the script that you launch (either manually or via a scheduled task). Typical syntax is like this:

    Get-SAMReport [module] [output]

For example

    Get-SAMReport Exchange OnScreen

The first thing this script does is collect a number of user defined variables, a style sheet layout and global functions. These are all stored in the _Assets folder and are universally applicable to all reporting modules:
  • Global_Variables.ps1*
    • Contains all of your relevant server names, email contacts etc.
    • Primary report colours, headings etc
  • Global_StyleSheet.ps1
    • All of the HTML format coding
  • Global_Functions.ps1
    • A central location for any functions that need to be called
*As a minimum, you need to customise the Global_Variables.ps1 script.

Then, depending on the module chosen, Get-SAMReport.ps1 will then parse all of the scripts in the relevant module's subfolder. These scripts are based on a standard template so the results can then be imported and aggregated to generate the final report. Any script in the specified module subfolder will be run, in the order listed. If you don't like a script, just remove it or rename the .ps1 extension.

Example of the folder structure

Modules and Templates
The framework is designed to work with any system that supports Powershell v3.0 or later.
For each system module there is a subfolder for individual scripts. There is a high level 'Module Variables.ps1' script which acts like the 'Global Variables' script, but is limited just to that module. Each of the remaining scripts are called in order and produce a standardised output. This output is very specific and must be in the supplied format. Currently the parent script can accept up to four separate results per child script:

  • Results Text (html formatted)
  • Results Data (html formatted table)
  • Results Alert (Alert, Warning, Good colour codes)
  • An attachment (found on any UNC path)
Each of these scripts contain further variables (such as servers or service names) and thresholds that you can customise. So feel free to tweak these to suit your environment. Have a look at some of the examples provided and you'll soon get a feel for the methodology.

NB. The scripts need to be stored and run from a server that contains the relevant management tools and Powershell plugins.

Scheduled Tasks
The reports are best suited to being run as a scheduled task. The typical syntax for running is as follows:

Start a program: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Arguments: -NonInteractive c:\SAMReports\Get-SAMReport.ps1 Exchange
Start in: c:\SAMReports\

There is a 'Scheduled Task Example.xml' file in the assets folder which can be imported to make this process easier.

Ensure the script is run manually at least once for each module you want to use. You will be prompted for your "Run As" credentials for that module. These will be saved using ConvertTo-SecureString for future use in a hashed 'ModuleCredentials.xml' file. To changed the saved credentials, remove this file and re-run script manually once more.

Example Plugin
This is a simple example showing the typical framework for a module plugin.

Once the results have been aggregated into the final report, you will be able to view the relevant data that you have gathered and also quickly see any Warnings or Alerts based on your thresholds. Even specific text with each section can be highlighted accordingly. The overall title of the report will also reflect the worst result, so for example if there were 8 sections and only one showed a Alert, the report title will be coloured as a Alert.

Here is an example of a full report

As I said earlier, this is a community driven project if you have any suggestion or module scripts you have created, I would love to include them here - with full mudos to you of course.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Wednesday 13 June 2012

Preventing Password Expirations with Custom Emails and Reports

One of the big sources of calls to the Helpdesk department is the fallout from expired passwords. Generally users will get a Windows message box at login warning about this, but I find that this basic prompt doesn't always work in practise. Firstly, by default it pops up way too early and is often more annoying for your users. Secondly, most people just tend to ignore it and often continue to do so until it is too late. Also, for environments that use Citrix published apps or terminal services sessions, there can be some delays in password replications and conflicts if users change their password at logon. This can lead to account lockouts and even more Helpdesk calls! Finally, if you happen to turn on some group policy features, this warning simply will not show up at all.

So, this project is about contacting your users via email and advising them with your own clear message that their passwords are about to expire. At the same time generate a simple report for the administrator, giving them a heads up to potential issues. The original script was sourced some time ago, so if I find the originator, I'll be sure to pass on all mudos.

Also note, that this script uses Quest's ActiveRoles. You can of course easily customise and use the native AD module. Once you're happy, set it up as a daily scheduled task. Ideally do this late in the afternoon, to remind users just before they are about to log off. Also have a look at customising the messages within the emails. You do want to keep this simple but informative. Keep in mind that since passwords can be sensitive and phishing is so easy, you don't want to establish bad behaviours (such as clicking on a hyperlink).

There are three broad sections in the script. The first is to email users whose passwords have expired. I find this a little counter intuitive, but some environments might find this handy. Perhaps they might still have Blackberry working or you might want simply want to send it as a record with information about how to avoid next time.

The second section is where it sends an email to each user whose password is expiring within your designated time. Personally I set this as less than 5 days. This is enough to cover weekend and part timers, but not so repetitive that it becomes annoying. Additionally, you might also have system accounts, so in these cases (where their isn't a valid email recipient), it will send the email to the administrator.

The final section is where it collects all of the users whose passwords are about to expire and all of the users whose passwords have expired, and wraps it up into a nice email report for the administrator. This can be handy, because you can see the people that are ignoring their emails as they just keep showing up in that report! A quick proactive phone call would be much appreciated by the user and the Helpdesk.

Here's the full script.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Thursday 7 June 2012

Discovering Client Connections with Lync 2010

In this post we'll discuss a number of ways to discover information about your Lync clients. One of the great things about Lync 2010 is the detailed monitoring and reporting that comes out of the box. However, one thing that is difficult to find, is comprehensive information about the growing list of clients that are connecting to your Lync servers.

So, what is a client exactly? Typically, this is going to be either a Lync enabled phone or the Lync software client running on your PC/Mac. But this could also be an Attendant console or something like a registered video conferencing endpoint. With the new Mobility functionality, this list grows dramatically with the inclusion of Blackberry, Windows Phone, iPhone/iPad and Android devices.

Why is this important? Firstly, because Lync is relatively new, there are a lot of changes and updates to the client software. By reviewing the version information of the clients connecting, you can quickly see which ones are out of date and need patching. I also find it useful to understand the uptake of certain initiatives, such as Mobility.

The Lync monitoring role does provide some insight into the client details. Amongst the number of standard reports is the IP Phone Inventory Report. This report is very detailed showing hardware, software and user activity. The only downside is that it is limited to phone agents.

Lync stores all of this information in SQL databases on the local Front End and SBA servers called RTCLocal. So, there is nothing stopping us doing a bit of querying ourselves right? Well, some people have already started doing this. Check out the neat bit of software from Stumper called Find Lync Versions. This utility does a basic SQL query to return the client connection information. It then parses the information against AD and DNS to give you a formatted table of all connected clients, usernames and computer names. For larger environments, this tool becomes a little limited because you need to run separate queries against every server in your environment that has client registrations.

After mobility was released, I wanted to keep an eye on the uptake and offer some personalised training. So it was important to see what devices were being used. At the time I could not find any easy way of reporting on this. So I asked our SQL guys to put something together that we could use to query all servers at the same time and return a list of meaning information. We then added this to the reporting services, along with the other Lync reports on our central SQL server. There is a lot of data in there, so we ended up just including filters for the Username, Server, Client Version Keyword or Client Type. The later is presented as a dropdown list, performing a fixed keyword match on the client version string.

  • Mobility               (keywords contain “RTCC/”)
  • Video Conf          (keywords contain “Polycom”)
  • Lync Client          (keywords contain “UCCAPI/”)
  • Lync Phone         (keywords contain “CPE/”)

The new report quickly allows us to do thing like "Show all users on Server 1", "Show all phones in the enterprise that are running version x", or "Show all users connecting with iPads" for example. Visibility is a wonderful thing!

Here is the base query code we used.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Wednesday 6 June 2012

Using multiple copy streams with Robocopy

This is a quick post to outline a technique I've used to migrate file servers using robocopy - or to be specific, lots of parallel robocopy streams.

The script works best when you have multiple 2nd level sub-directories contained in the root directory. The VBS file below parses the directory names into seperate robocopy command line statements inside a new batch file. When the batch file(s) are run, a seperate robocopy stream is processed for every sub-directory at the same time.

All of the usual robocopy command switches can be used of course. For one off jobs, these multiple parallel streams are much faster than a single stream. It's also great for syncronising file stores if run as a sheduled task.

Here is the code.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Tuesday 5 June 2012

Getting Unassigned Numbers in Lync 2010

So picture the scenario, you've got a new user starting tomorrow and you need to assign them a phone number. But which number? One of the complexities with any domain integrated VOIP system is keeping some sort of control over the allocation of phone numbers. You may very well have an up to date phone list, but Active Directory and Lync don't really care about your über Excel skills.

Check out Ståle Hansen's blog post for his original script that did a brilliant job solving this problem. The updated script below runs from your Windows 7 machine and presents a list of phone numbers that are either Assigned or Unassigned for your choosing.

In large enviornments covering multiple sites, this could still be a complex result set. So rather than just throwing out a list of potentially hundreds of numbers, the script compares the numbers it finds against the "Unassigned Number Range" feature in Lync. This is primarily used to play a message or redirect a call if someone accidentally calls a number that has not been assigned to anyone. Here's a Technet article with more information.

In our environment, we simply redirect these calls to reception. The ranges were setup for each site, corresponding to each contiguous block of numbers that we had been allocated by the phone company eg 1234 1200 to 1234 1299. We're not going to do any redirection with this script, just use the ranges to provide some measure of control for selecting and displaying results.

The script checks a series of phone number repositories using typical Lync shell cmdlets such as Get-CsUser and Get-CsAnalogDevice. All up this includes:
  • User numbers (including Private Number)
  • Analogue Devices
  • Common Area Phones
  • AutoAttendant numbers
  • Dial In Access Numbers
  • Trusted Application Endpoints
  • Response Groups
As the script runs it queries each range, advises how many numbers are in use and prompts for an action to either show the Unassigned Numbers, the Assigned Numbers or to skip that range and move on to the next one. 

Here is the complete code.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Friday 1 June 2012

Using Get-WinEvent and XML filters to query Event Viewer

In previous roles in IT support and network administration I quickly leaned the benefit of Windows Event Viewer. Fundamentally for me it served two purposes; a retrospective log where I would go and seek an answer to something that had just happened, or alternatively a proactive log where I could get a heads up on potential issues.

Proactive is always good, right? The problem is there is only so much time in the day to spend scrolling through all of that noise. There needs to be a process of filtering and reporting, which allows you to get to important information efficiently. Now, there are a number of commercial programs around that manage this already, so if your scale and budget are so inclined it's a very valid solution. Event Subscriptions are also another method of collecting logs from dispersed machines. Combined them with tasks and you've got a nice little system for gathering and alerting.

In this post however, I'm going to look at gathering event logs using powershell with the get-winevent cmdlet. More importantly, we're going to look at including an XML filter in your query to make the whole process much, much faster. Finally, I've added some code to export the logs to a CSV file or an email for reporting purposes.

The example below is a mini project to collect print server job logs as it serves as a good example of the scenario above. By default the individual user job logs are not enabled. So the first thing we need to do is turn on Print Services Operational logging via Event Viewer > Applications and Service Logs > Microsoft > Windows > Print Service > Operational > right click to Enable Log.

Hands up who loves the way you can doing something in a GUI and it produces the code for you in the background? Well, Windows Event Viewer has a neat way of doing GUI based filtering, which result in XML based queries that you can use in your coding.

Open up event Viewer and create a basic filter on an EventID through Actions > Filter Current Log. Here's an example using EventID 307 (which is a successful print job).

If you then click on the XML tab at the top, you will see the XML query string that is being used. This is what we need to copy into the get-winevent cmdlet.

In your script, the string needs to simply be defined as a variable and enclosed with an apostrophe, for example:

The second part of this process is working out what parameters are contained in the event, so you can define them as variables for manipulation in your script. So, going back to one of the events in the log simply click on the Details tab. Here you will see all of the parameters that can be retrieved in a Friendly View.

I've masked out some details in the above example,but you can easily see how it is laid out. The syntax for your script is also straight forward. Firstly a single line for the xml conversion, then simply call the parameters working through the levels of the xml tree. In this case User Data > DocumentPrinted > Parameter. For example:

So, here is the complete code for this project, including writing the output to a CSV file and attaching it (or including it as the body), to an email

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Sunday 27 May 2012

Process List and Kill

If you haven't used the awesome set of PsTools by Mark Russinovich, stop reading this immediately and check them out. I'll wait.

Two of my favourites are PsList and PsKill. The first lists running process information and the second kills a process (based on it's Process ID or PID). The really cool thing is that you can run the same commands against remote machines (assuming you have appropriate credentials).

Combine the two in a user friendly script and you've got yourself an instant solution for identifying and stopping rogue processes. I've also added in some logging so you keep an eye on the history of troublesome machines.

When you first launch the script it prompts you for the machine name (or IP address), that you want to investigate.

This is then passed into a command line execution of PsList. There are a bunch of switches available, in this example I run the capture for 10 seconds with a refresh every 2 seconds. It's good to get a few refreshes in there, to avoid a false positive. The resulting text file opens up and displays all of the running process with details such as the Name, Process ID, CPU, Memory and Page Faults.

In the example above you can see WINWORD Process ID 9924 is consuming 48% of the CPU resources. The server in question has 2 vCPUs, so this is definitely a rogue process consuming an entire core. Checking the other captures confirms this process is not going anywhere.

The next prompt confirms if you want to kill a process and if so asks for the PID. This gets passed into a command execution of PsKill. Bang! That's it, the process will be killed immediately.

Here's the script.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Saturday 26 May 2012

Server Inventory from Active Directory

This is a very short and sweet litle script that is great for pulling information about your servers (or workstations for that matter), from Active Directory.

The example below returns a number of properties including Server Name, Description, IP address, OS Level, When Created and Last Logon. There are heaps of properties available, so experiment and find what you need.

         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Network Printers App

Over the years I went through various iterations of methods for deploying network printers to user's computers. The day in day out stuff was pretty straight forward, but occasionally you have to setup a new user, they would move locations or perhaps I'd install a new print server and cut a whole office over. I had a bunch of scripts and used delivery techniques from manual installs, links in emails, group policy deployment and even startup scripts that made intelligent updates based on the current setup (have to admit I did like that one ;)

Each time though, it was a new mini project. I want to build something that would be more centrally managed and dynamically update based on the setup of the print servers. So I built a network printer application as a centrally stored HTA (VBS and HTML), and put a shortcut on every ones desktop. 

It was sold to the users with the following benefits and was very well received:

  • Find a Printer (based on feature or location)
  • Lookup your Printer Status (print queues, paper jams, low toner etc)
  • Install a new printer (in 2 clicks!)
  • Speed up your PC (remove old printers, or printers from another office)
This is what the app looks like:

1. The Print Server area automatically selects the print server in the user's office. It also has several Feature checkboxes, and a Keyword search. So you can do a lookup for say a Colour printer in the Melbourne "Marketing" department

2. Depending on the print server selected above, a list of Available Printers appears (yes, we use movie star names - makes them easy to remember). Selectable check boxes only show next to any printers that match the filters used. Each name is also a hyperlink to that printer's web page to lookup status etc

3. This section shows the current Default Printer and allow it to be changed

4. The first Option here determines whether the printer is just added or if the drivers are reinstalled on the user's PC. The second option is a Clean Up trigger, which removes any other (network printers), that are not selected above.

5. The Information area kicks everything along, open the user's 'Devices and Printers' or resets the form. It also shows relevant information on the current install status, whether there are any printers attached to a legacy print server (handy for migrations), whether there are any printers attached to a print server in another site (slow!) and finally whether any of the currently installed printers have any status issues.

The script itself is a HTA, which is a self contained application built using a combination of VBS and HTML for the layout. Calls to the print servers are via a simple net view \\printserver command line request, which is then parsed for relevant information. Of note here is the Comments section on each printer on the print server, as this is where the Feature and Keyword lookups refer to. Information on the local printers is sourced through WMI queries and actioned via VBS statements.

The example I have is for four sites and there is a fair bit of code around lookups of specific site information, loading the form and getting the checkboxes set correctly. As always tweak as needed in your environment.


         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Friday 25 May 2012

Departing User Script

Following in the user management theme, this is a script that manages the workflow for a departing user.

I found a need to standardise this process because it was all too easy to miss a step leaving an account open or email going unchecked. As always, mash it up to suit your environment.

Like the earlier script, the info is loaded from a basic CSV file, with a focus on Active Directory, Exchange and Lync.

Summary of steps:
  • Import user info and yes/no triggers from a csv file
  • Move user Profile and Home directories to an archive share
  • Disable Enterprise Voice
    • Removes Unified Messaging in Exchange
    • Removes user from Lync
  • Manage email continuity
    • Gives mailbox access to a nominated user and advises them via email
    • Adds an Out of Office auto reply, with redirection info to nominated user
    • Adds a calendar reminder to eventually disable the email address
    • Alternatively, can just disable email address immediately
  • Archive Mailbox
    • Removes user from Global Address Book
    • Moves the user's mailbox to an archive database
  • Disable AD account
    • Moves to an archive OU
    • Removes AD details (handy to clean org chart or free up IP phone number)
    • Removes from groups and distribution lists
    • Resets user's password
  • Send a summary report and log file via email


         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^

Thursday 24 May 2012

New User Creation Script

This powershell script is very handy for setting up new users in AD, Exchange and Lync.

It's customised to my environment and has saved us a ton of time. I'm sure many will have different requirements, so add, pull out and modify the bits you need.

If you're running RSAT from Windows 7, ensure to load the Active Directory module for Windows Powershell and have appropriate credentials.

The CSV file needs to be created up front with the at least the appropriate header info. As the script runs, it will open the CSV file to add/modify the user(s) details. I get our HR department to provide all of the required info in a table format, so a quick copy/paste/save is all that is needed. Also ensure to use samAccount names in the user lookup fields (manager etc).

Here is a summary of what it does:
  • Imports new user(s) info from a csv file
  • Creates new user account and mailbox in Exchange
  • Enables for Unified Messaging
  • Add mailbox access to thier manager's mailbox
  • Populates all AD fields
  • Adds to security/distribution groups (uses another similar user to copy memberships from)
  • Creates user profile and home directories, with permissions and ownership
  • Adds user to Lync, and setups features such as enterprise voice, policies etc
  • Creates a summary report and a log file and emails it to admin, HR etc


         (oo)  ok
   /------\/  /
  / |    ||
 *  /\---/\
    ^^   ^^