Writing CMTrace format Log files with Powershell

Anyone who has administered a little SCCM in their time, would be be familiar with the tool CMTrace or SMSTrace. CMTrace is a tool that comes with System Center Configuration Manager. It allows you to view the myriad of logs files that SCCM generates in a consistent and easy to read format. Being used to the log format that CMTrace generates, I thought it would be a great idea to use that format for logging Powershell script actions and errors.

I hunted around the web and found a few versions of a log function using CMTRace. The best implementation that I found was from Russ Slaten at the System Center Blog site. It works really well but I wanted to add some different functionality.

CMTrace.exe is part of the System Center 2012 R2 Configuration Manager Toolkit, which I believe anyone can download. If you have System Center Configuration Manager installed in your environment, you can also grab it from the \\”SiteServer”\Program Files\Microsoft Configuration Manager\tools\cmtrace.exe.

There are a few different use cases for when logging is handy: -

  • Running Powershell scripts as Scheduled Tasks.
  • Auditing automation centrally in a team environment.
  • The output of a log could be used as part of change management processes.
  • Debugging locally and remotely

I’ll start off by posting the script. Below I’ll go into some information that might help in using the script.

**NOTE: This has only been tested on Powershell v5.0. The information stream is a new feature of Powershell v5.0.**

Here is the script: -

I’ve included a help file inline to help with calling the function.

Where does the log file get created?

The function by default will log to $Env:temp\powershell-cmtrace.log. You can however pass a file location to the function if you would like to the log file in a different location.

What does the output look like on the host?

Here is an example.

Why does Error only log one line back to the host, where is all the ErrorRecord informaiton?

I wanted to write back to the host in a consistent fashion. The error record is still there I’m just not passing it back to the host. The full error record gets put in the log file and you can view that information by clicking on the Error entry and looking at the window down the bottom of CMTrace. Also, you can still access the error information in the host by using the $Error variable. If it were the last error you would access it by using the first index of the $Error variable. eg. $Error[0].

What does the output to the log file look like?

It looks like this. Notice the Error information is in the box down the bottom.

I don’t want to see the output on the host, I just want it to log in the CMTrace format.

There is a parameter switch called WriteBackToHost. By default it’s set to True, but if you don’t want to see the output then set this to false.

How do I call this function?

To call this function, either dot source it, run it from ISE and then call it, put it in your profile or pop it in a module and Bob is your uncle.

Gimme some examples of how to use the Write-CMTracelog function.

Here are some examples of how you would use this advanced function that are in the help section of the function.

Examples:

The below example shows how to output a verbose message.

This example shows how to use the Preference variables with the Write-CMTracelog function. It should obey any preference variables that are set in the same scope from where the function has been called.

This example shows how to use the function with a terminating error by using the $Error variable in the message parameter.

 

Hope this function helps you out. Feel free to use and modify to suit your needs.

Sources:

http://blogs.msdn.com/b/rslaten/archive/2014/07/28/logging-in-cmtrace-format-from-powershell.aspx
https://www.microsoft.com/en-us/download/details.aspx?id=50012
http://blogs.technet.com/b/heyscriptingguy/archive/2015/07/04/weekend-scripter-welcome-to-the-powershell-information-stream.aspx

Getting the Definition of a ScriptProperty in Powershell

Sometimes when you are checking an objects members you will come across the membertype ScriptProperty. I recently ran across this when I was troubleshooting some issues I was having with the Get-Hotfix cmdlet. When you pipe Get-Hotfix to Get-Member you can see that the property InstalledOn has the membertype ScriptProperty. I wanted to know what was actually going on in that definition but as you can see from the screen shot below it's truncated.

I did a bit of reading and it turns out you can get that information by running the following set of commands.

This will then print out the definition of the ScriptProperty.

The other way to view this would be to crack open the types.ps1xml and search for the bit you can see as this is where the scriptproperty is set. I used Notepad ++ to make it easier to find.

Powershell 5.0 with Chocolatey Sauce = Delicious!

Since the release of Windows 10 I have spent some time playing with the Production Preview of Powershell v5.0. The new PackageManagement module is a great addition to this version of Powershell as it allows you to install software from the Chocolatey resource. Documentation and examples is a bit scarce at the moment but I found some cmdlets have some online help files.

Here is what I’ve found so far: -

I’ll start by making sure I’m on Powershell 5.0.

$psversiontable run in powershell

Figure 1

Let’s check what cmdlets the new PackageManagement module offers us.

Using Get-Command with the Module property to get the list of cmdlets in the PackageManagment module.

Figure 2

Get-PackageSource gets a list of package sources that are registered. Here is the online help for this cmdlet.

Get-PackageSource cmdlet example

Figure 3

Only the PSGallery source is available. The Powershell Gallery is a great resource in itself. Making it really easy to find useful modules in a central location. That’s a topic for another day however. Here is the link if you’d like to check out what the Powershell Gallery has on offer.

The other cmdlet that interested me was the Get-PackageProvider cmdlet. The Get-PackageProvider returns a list of package providers that are connected to PackageManagement. Out of the box in the preview you get Msi, Msu, Programs and PSModule. I wasn’t entirely sure what was the difference but the About_Oneget online help file helped out here. The package provider is the package manager and the package source is the location the package provider connects too.

An example of running the Get-PackageProvider cmdlet.

Figure 4

Let’s try and add Chocolatey as a package provider. The force and forcebootstrap parameters can be used interchangably according to the online help file for the Get-PackageProvider cmdlet.

 

An example of using the Get-PackageProvider to add the PackageProvider Chocolatey.

Figure 5

Now we have a Chocolatey package provider and if we use the Get-PackageProvider cmdlet again we can see it’s been added.

Now the Chocolatey Provider is added.

Figure 6

When I run the Get-PackageSource cmdlet again I can also see that there is a Chocolatey package source as well.

The Chocolatey PackageSource has been added.

Figure 7

In Figure 7, you can see the Location has been truncated so I can see the actual location better by piping to the Format-List cmdlet. Notice in Figure 8 the “IsTrusted : False” property. What does that mean? IsTrusted:False sounds bad. Below is an excerpt from the Chocolatey site about whether you should trust the Chocolatey package source. If you really wanted to be safe you would set up your own repository internally and then add tested software to that repository. Kind of like you would already do with SCCM or another application deployment system.

How do I know if I can trust the community feed (the packages on this site?) Until we have package moderation in place, the answer is that you can’t trust the packages here. If you require trust (e.g. most organizations require this), you should have an internal feed with vetted packages using internal resources. You should always decide whether you trust the maintainer(s) of the package, and even then you may want to inspect the package prior to installing. You can inspect packages easily with nuget package explorer or by clicking download on the package page (and then treating the nupkg as a zip archive).

From <https://chocolatey.org/about>

 

Using the Format-List cmdlet to better see the values of the properties.

Figure 8

Now we have added the Chocolatey package provider and the Chocolatey package source, let’s see what we can do with the Find-Package cmdlet. Let’s look for Notepad++.

Using the Find-Package cmdlet to find Notepad++

Figure 9

Cool, it finds it. But what if you didn’t know really what Notepad++ was. Let’s see what the summary property says about Notepad++.

An example of using Select-Object to find more information about the Package.

Figure 10

Because the Chocolatey package provider isn’t trusted. Let’s save the package to our local hard drive. First I have to create the location that I’d like to save the package too.

Using the Test-Path cmdlet to test the location and the New-Item cmdlet to create it if it doens't exist.

Figure 11

Now that the location has been created let’s use the Save-Package cmdlet to save it to the location. I’ll use the -IncludeDependencies parameter to make sure I get all the bits I need to install Notepad++.

Using the Save-Package cmdlet to save the package locally so that you can have a look at it's files.

Figure 12

Let’s check what files we have in our saved location. In Figure 13 we can see that there are 2 files with .nupkg extensions. I wasn’t sure what sort of file .nupkg extension was. I’ve heard of Nuget but I’ve never really used it. Turns out you can extract the contents of a .nupkg file just like a zip file. Excellent, I know that the Production Preview of Powershell 5.0 that shipped with Windows 10 has an Expand-Archive cmdlet.

An example of using the Get-Childitem cmdlet.

Figure 13

In Figure 14, you can see I’ve tried to use the Expand-Archive cmdlet to extract the contents of the .nupkg file but the red text tells me that only the .zip file extension is supported. Oh well, it was worth a shot. You can also see in Figure 14 the use of the PipelineVariable parameter. This is the first time I’ve used that parameter and it allows me to store the current pipeline object into the variable I’d like to use. You can read about it more over on Keith Hill’s blog.

An example of trying to use the Expand-Archive cmdlet. Also an example of using the -PipelineVariable parameter.

Figure 14

So, I can’t extract using the built in Expand-Archive cmdlet but I still have my trusty 7zip executable. In Figure 15 you can see an example of calling 7z.exe from within a powershell console. It works like a charm.

An example of using 7z.exe from within Powershell.

Figure 15

Now that we have extracted the contents I can see a couple of files but nothing really sticks out except the .ps1 files. I can use the Get-Content (or Cat alias) to print the contents of the file to the Powershell Console.

An example of using the Get-Content cmdlet.

Figure 16

So we can see that all the ps1 file is doing is downloading the Notepad++ installer from the Notepad++ website. Sounds legit. If you were still a little bit suspect about the other files, and you didn’t have Real Time monitoring turned on, you can always scan the directory manually with Windows Defender from the Powershell Console like I have done in Figure 17.

An example of using Windows Defender to scan files manually from Powershell. I believe this would work with System Center Endpoint Protection as well.

Figure 17

After going off into the weeds a little, I’ll now just get on with using the Install-Package cmdlet to finally install Notepad++. After playing with this module I now am excited to use these cmdlets to script installing all the software I normally use. That’s for another day however. Hope this helped.

An example of using the Install-Package cmdlet.

Figure 18

Image Source: https://upload.wikimedia.org/wikipedia/commons/thumb/f/f2/Chocolate.jpg/308px-Chocolate.jpg

Backing up Active Directory in Windows Server 2012 R2 with Powershell

Backing up Active Directory in Windows Server 2012 R2 with Powershell is now really easy thanks to the Windows Server Backup cmdlets provided in Powershell. Windows Server Backup allows you to create a Scheduled backup or a one time backup. In this example, I’ll be doing a one time backup but scheduling via a scheduled task to allow for more flexibility and I’ll be backing up the system state of the server.

The first thing that you will need to do if you haven’t done so already is to install the Windows Server Backup feature.

Once that is done, below is a little script that I created for myself that will backup a server’s system state. If this is a domain controller, you could use the system state backup to restore Active Directory if needed.

Here are some screen caps of what it looks like when it is running.

To finish things off, you can then create a scheduled task to run the script at a time you would like.

I’ve already created a post to show how to create a scheduled task using Powershell. You can find that here.

For further information or to checkout the material I used to create this script please click on the following links: -

Windows Server Backup Cmdlets in Windows Powershell
http://technet.microsoft.com/en-us/library/jj902428.aspx
Using Windows Server Backup Cmdlets
http://technet.microsoft.com/en-us/library/dd759156.aspx
Windows Server Backup Step by Step Guide for Windows Server 2008 R2
http://technet.microsoft.com/en-us/library/ee849849(WS.10).aspx

 

 

Export-DnsServerZone fails to export

With PowerShell v3 comes some new DNS cmdlets. One of them is the Export-DnsServerZone cmdlet. This replaces some of the functionality of the old “DnsCmd” command line utility.

Actually, if you run DnsCmd on Windows 2012, it actually tells you that if you currently use DnsCmd.exe to configure and manage the DNS server, Microsoft recommends that you transition to Windows PowerShell.

So, on to Export-DnsServerZone. I thought great, that’s excellent news, instead of having to worry about getting PowerShell to execute the old dnscmd.exe and worry about its arguments etc., I’ll use the built in cmdlet to do the job.

Here is an example of what the command looks like.

If you were to substitute the name for the DNS zone you would like to export, and the filename for something that better describes your zone, that example will output a text file in to the %windir%\system32\dns folder.

So then, you can have your backup software come along and back it all up for you and everyone is happy.

Except, if you would like to modify that –Filename parameter to have it point to an actual file location like “C:\export.txt”. It doesn’t seem to work and you will get an error saying “Export-DnsServerZone : Failed to export the zone content for <your domain> on server <your server> to the file

<your file location>”

When you look up the online help for the cmdlet, it does specify that you can put a file path in the parameter. As shown below.

It doesn’t seem to accept UNC path either.

But it does seem to accept, a relative path. (The following command should put the text document in the root of C:\.

Here is the link to the online help for the Export-DnsServerZone cmdlet.

http://technet.microsoft.com/en-us/library/jj649939(v=wps.620).aspx

Active Directory Health Check automation via Powershell

It’s important to run some Active Directory Health checks on your domain. To that end, I thought it would be great to generate a weekly report that contained a DCdiag, a Repadmin and Best Practice Analyzer report. This could be done via a Scheduled task. It could then run once a week and then email you with any issues. A great way to keep on top of the health of your environment and to make sure no little niggling errors are hiding just under the covers, waiting to destroy your environment.

The hardest part of the script was executing the cmd prompt command via the script. Passing in arguments is messy in Powershell at the best of times, but passing in arguments with spaces and having to escape the correct characters etc is very tedious. So, as a disclaimer, this script is a work in progress. It works, but by no means is it an example of Powershell Best Practice. (I’ll keep a tinkering on it, and if anyone has any suggestions please leave a comment.) Hopefully, though, someone other then me may find this useful.

There are also a few caveats to be aware of. This script, the way it is presented here, will only work on Powershell v3. I found this out because in an effort to get the BPA cmdlets working, I realized that the syntax for the commands are different in the different versions of Powershell. If you would like to get this to work on Powershell v2, you just need to change the -ModelID parameters to -ID. A quick “Get-Help Invoke-BPAModel” should sort that out pretty swiftly. Also, the file locations are hard coded at this point.

You can find some more information about DCDiag command here.
You can find some more information about the Repadmin command here.
Here is some information aswell about running the BPA via Powershell

Installing the Hyper-V Feature via Powershell on Windows Server 2012

 

Open up a Powershell Console as an Administrator.

 

We can use the Get-WindowsFeature cmdlet to find what Hyper-V features are available for installation.

 

PS>Get-WindowsFeature –Name hyper-v*

 

This will show the Hyper-V features that we can install. 

Once we know what we would like to install. We can use the Install-WindowsFeature cmdlet to install the feature. We can use the IncludeSubFeature and IncludeManagementTools parameters to install all subfeatures and management tools at the same time. The –Restart parameter will make the machine reboot once it has finished installing.

 

PS>Install-WindowsFeature –Name Hyper-V –IncludeSubFeature –IncludeManagementTools –Restart

The Feature will then install. 

After a reboot, you should be able to see the Hyper-V Manager in your Start Page. 

Using Powershell to search a log file for an error and then email you

This little script I used when I was having a problem with my TV Tuner card on my home server. Every now and then it would stop working and it was a real pain to come home and find that the shows I had set to tape hadn't recorded because the card stopped working. So this script would email me to let me know that it was time to perform some percussive maintenance on my usb tv tuner card again. 

Running a Powershell Script via a Scheduled Task

This blog post will show how to run a Powershell Script via a Scheduled task on a Windows 2008 R2 Server.

 

On your Windows 2008 Server, or Windows 7 machine. Open the Start Menu and then type in 'task' into the start search field. Then select Task Scheduler.

Select Create Basic Task. In the Actions Pane on the right hand side of the screen.

Type in a Name and a description for the Scheduled Task. Once done, click Next.

Set how often you would like the task to run. Then click Next.

Select Start a Program. This is so we can kick off the powershell.exe. Click Next.

In the program field type:

Powershell.exe

 

In the add arguments field type:

-Noninteractive -NoProfile -command "& '<path to .ps1 file>'"

 

Click Next.

Tick the Open the Properties check box then click Finish.


 

Go through each individual tab if you need to.

 

On the general tab, make sure you set the appropriate user to run the script.

 

Be sure to take into consideration whether you want the script to run only when a user is logged in or not.

Check the Triggers tab.

Check the Actions tab.

Check the conditions page and set any conditions you may want to put on the task.

Double check the setting page. And then click ok.

Put in the credentials you would like to run the scheduled task under.

The task is now set to run. This will now execute your powershell script at the time and date that you specified.

 

YOU WIN!