PowerShell can be used in a diverse set of circumstances. Sometimes PowerShell is used to establish an ongoing process, such as managing users. In such a circumstance, logging becomes rather crucial, both in terms of identifying errors but also in terms of capturing what was successful to provide reports. The Windows Event Log is a great existing tool for such a task and PowerShell is capable of working with it in many different ways.
Establishing an Application Log
Let’s imagine that we have a system that we want to provision users and it requires numerous scripts to manage the overall process. We’ll call the overall capability set “Provisioning” and we’ll call the three sub-processes “User Provisioning,” “Policy Assignment,” and “Licensing.” We’ll be using a Windows Server system as a host to execute the related scripts and we want to create a custom Application in the event log:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
New-EventLog -LogName "Provisioning" ` | |
-Source "User Provisioning" | |
New-EventLog -LogName "Provisioning" ` | |
-Source "Policy Assignment" | |
New-EventLog -LogName "Provisioning" ` | |
-Source "Licensing" |
Writing Event Log Entries
Within our scripts, we can use various means to identify items that we would like to capture in the event log. We could use Try/Catch blocks. If we’re provisioning a user, we could run the following at the end of the Try block to denote the successful provisioning of a user:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Write-EventLog -LogName "Provisioning" ` | |
-Source "User Provisioning" ` | |
-EntryType Information -EventId 1000 ` | |
-Message "User provisioned: ${UserPrincipalName}" |
If we attempted to license a user and it failed, we could run the following in the Catch block:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Write-EventLog -LogName "Provisioning" ` | |
-Source "Licensing" ` | |
-EntryType Error -EventId 3300 ` | |
-Message "No licenses available for user: ${UserPrincipalName}" |
Taking Action
In some instances we may simply choose to report on items daily, weekly, or monthly. This would work well for getting a summary of the number of users provisioned. We could write a script for a scheduled task to execute on the desired interval and pull the requisite information like so:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-EventLog -LogName "Provisioning" ` | |
-Source "User Provisioning" ` | |
-EntryType Information ` | |
-After (Get-DateTime -format %m/%d/%Y) |
We could store this in a variable, pass it through Select-Object to grab the specific attributes that are interesting, and through Where-Object to filter the results, then make a report with ConvertTo-Html.
That is great for situations where things are working and we just want a report. However, when things go wrong, we likely want to be notified in a more timely manner.
Establishing Triggers
A scheduled task need not only be based on a time of day, it can also be triggered by the instance of an event. Since this is specifically what we are looking to do, this comes in handy. In order to grab the proper information, we could just grab the last instance of an event from the event log with Get-EventLog, or we could use some of the capabilities of the trigger to kick off our script and pass the specific event log entry to it. There are many ways to do this, but I find that the most extensible way is to pass the LogName and Index to the script. With these pieces of information we can grab the exact event log entry and take away all of the guess work.
The problem that we will encounter here is that with the GUI for Scheduled Tasks we cannot do this. So, the way that I handle this is to create the scheduled task and then execute the following script that will export the task to an XML file, delete the original task, modify the XML file, and then re-create the task with the XML file.
Update-ScheduledTask -Name <ScheduledTask>
This will execute the supplied script and pass whatever event log entries that we are watching for to it. Then we can add parameters to that script to accept the LogName and Index parameters and run the follow to grab the full event log entry and parse the interesting information from it and take an action:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-EventLog – LogName ${LogName} -Index ${Index} |
After which, we could send an email.
Alternatively, one could create a monitoring pack in SCOM or other solutions that monitor for such events and define actions within.
While this is a fairly simple set of tasks, together they can be used to create quite sophisticated solutions that make our processes more robust.
SPONSOR: Do you want a simple domain name registration solution without constant up-selling and keeping your data private by not selling it and giving you free WHOIS privacy? Sign up with Hover and and get $2 off of your first order. You’ll get a great a great experience and be supporting this site.