Manage and Monitor PowerShell Scripts

Anyone who knows me knows that I’m a fan of PowerShell. “Fan” is a diminutive version of the word “fanatic,” and in this instance both are true. That’s why I was so excited to see that PowerShell script output is now supported in Server Configuration Monitor (SCM).

Since SCM’s release, I’ve always thought it was a great idea to monitor the directory where you store your scripts to make sure they didn’t vary and to validate changes over time, even going in and reverting them in case there was a change without approval. However, that part was available in the initial release of SCM. Using PowerShell with SCM, you can monitor your C:\Scripts\*.ps1 files and get notified when any deviate from their baselines.

Using PowerShell scripts to pull information from systems you’re monitoring is only limited by your scripting prowess. But let me say this plainly: You don’t need to be a scripting genius. The THWACKRegistered members are here to be your resources. If you have something great you wrote, post about it. If you need help formatting output, post about it. If you can’t remember how to get a list of all the software installed on a system, post about it. Someone here has probably already done the work.

Monitoring the Server Roles

Windows now handles many of the “roles” of a machine (Web Server, Active Directory Server, etc.) based on the installed features. There never was a really nice way to understand what roles were installed on a machine outside the Server Manager. This is especially true if you’re running Windows Server Core because it has no Server Manager.

Now, you can just write yourself a small PowerShell script:

Get-WindowsFeature | Where-Object { $_.Installed } | Select-Object -Property Name, DisplayName | Sort-Object -Property Name

…and get the list of all features displayed for you.

Name                      DisplayName

----                      -----------

FileAndStorage-Services   File and Storage Services

File-Services             File and iSCSI Services

FS-Data-Deduplication     Data Deduplication

FS-FileServer             File Server

MSMQ                      Message Queuing

MSMQ-Server               Message Queuing Server

MSMQ-Services             Message Queuing Services

NET-Framework-45-ASPNET   ASP.NET 4.7

NET-Framework-45-Core     .NET Framework 4.7

NET-Framework-45-Features .NET Framework 4.7 Features

NET-WCF-Services45        WCF Services

NET-WCF-TCP-PortSharing45 TCP Port Sharing

PowerShell                Windows PowerShell 5.1

PowerShell-ISE            Windows PowerShell ISE

PowerShellRoot            Windows PowerShell

Storage-Services          Storage Services

System-DataArchiver       System Data Archiver

Web-App-Dev               Application Development

Web-Asp-Net45             ASP.NET 4.7

Web-Common-Http           Common HTTP Features

Web-Default-Doc           Default Document

Web-Dir-Browsing          Directory Browsing

Web-Dyn-Compression       Dynamic Content Compression

Web-Filtering             Request Filtering

Web-Health                Health and Diagnostics

Web-Http-Errors           HTTP Errors

Web-Http-Logging          HTTP Logging

Web-ISAPI-Ext             ISAPI Extensions

Web-ISAPI-Filter          ISAPI Filters

Web-Log-Libraries         Logging Tools

Web-Metabase              IIS 6 Metabase Compatibility

Web-Mgmt-Compat           IIS 6 Management Compatibility

Web-Mgmt-Console          IIS Management Console

Web-Mgmt-Tools            Management Tools

Web-Net-Ext45             .NET Extensibility 4.7

Web-Performance           Performance

Web-Request-Monitor       Request Monitor

Web-Security              Security

Web-Server                Web Server (IIS)

Web-Stat-Compression      Static Content Compression

Web-Static-Content        Static Content

Web-WebServer             Web Server

Web-Windows-Auth          Windows Authentication

Windows-Defender          Windows Defender Antivirus

WoW64-Support             WoW64 Support

XPS-Viewer                XPS Viewer

This is super simple. If someone adds or removes one of these features, you’ll know moments after it’s done because it would deviate from your baseline.

Monitoring Local Administrators

This got me thinking about all manner of other possible PowerShell script uses. One that came to mind immediately was local security. We all know the local administrator group is an easy way to have people circumvent security best practices, so knowing who is in that security group has proven difficult.

Now that we don’t have those limitations, let’s look at the local admins group and look at local users.

Get-LocalGroupMember -Group Administrators | Where-Object { $_.PrincipalSource -eq "Local" } | Sort-Object -Property Name

Now, you’ll get returned a list of all the local users in the Administrators group.

ObjectClass Name                         PrincipalSource
----------- ----                         ---------------
User        NOCKMSMPE01V\Administrator   Local
User        NOCKMSMPE01V\Automation-User Local

Now we’ll know if someone is added or deleted. You could extend this to know when someone is added to power users or any other group. If you really felt like going gang-busters, you could ask for all the groups, and then enumerate the members of each.

Local Certificates

These don’t have to be relegated to PowerShell one-liners either. You can have entire scripts that return a value that you can review.

Also, on the security front, it might be nice to know if random certificates start popping up everywhere. Doing this by hand would be excruciatingly slow. Thankfully it’s pretty easy in PowerShell.

$AllCertificates = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse

# Create an empty list to keep the results

$CertificateList = @()

ForEach ( $Certificate in $AllCertificates )

{

    # Check to see if this is a "folder" or a "certificate"

    if ( -not ( $Certificate.PSIsContainer ) )

    {

        # Certificates are *not* containers (folders)

        # Get the important details and add it to the $CertificateList

        $CertificateList += $Certificate | Select-Object -Property FriendlyName, Issuer, Subject, Thumbprint, NotBefore, NotAfter

    }

}

$CertificateList

As you can see, you aren’t required to stick with one-liners. Write whatever you need for your input. As long as there’s output, SCM will capture it and present it in a usable format for parsing.

FriendlyName : SolarWinds-Orion
Issuer       : CN=SolarWinds-Orion
Subject      : CN=SolarWinds-Orion
Thumbprint   : AF2A630F2458E0A3BE8D3EF332621A9DDF817502
NotBefore    : 10/12/2018 5:59:14 PM
NotAfter     : 12/31/2039 11:59:59 PM

FriendlyName :
Issuer       : CN=SolarWinds IPAM Engine
Subject      : CN=SolarWinds IPAM Engine
Thumbprint   : 4527E03262B268D2FCFE4B7B4203EF620B41854F
NotBefore    : 11/5/2018 7:13:34 PM
NotAfter     : 12/31/2039 11:59:59 PM

FriendlyName :
Issuer       : CN=SolarWinds-Orion
Subject      : CN=SolarWinds Agent Provision - cc10929c-47e1-473a-9357-a54052537795
Thumbprint   : 2570C476DF0E8C851DCE9AFC2A37AC4BDDF3BAD6
NotBefore    : 10/11/2018 6:46:29 PM
NotAfter     : 10/12/2048 6:46:28 PM

FriendlyName : SolarWinds-SEUM_PlaybackAgent
Issuer       : CN=SolarWinds-SEUM_PlaybackAgent
Subject      : CN=SolarWinds-SEUM_PlaybackAgent
Thumbprint   : 0603E7052293B77B89A3D545B43FC03287F56889
NotBefore    : 11/4/2018 12:00:00 AM
NotAfter     : 11/5/2048 12:00:00 AM

FriendlyName : SolarWinds-SEUM-AgentProxy
Issuer       : CN=SolarWinds-SEUM-AgentProxy
Subject      : CN=SolarWinds-SEUM-AgentProxy
Thumbprint   : 0488D26FD9576293C30BB5507489D96C3ED829B4
NotBefore    : 11/4/2018 12:00:00 AM
NotAfter     : 11/5/2048 12:00:00 AM

FriendlyName : WildcardCert_Demo.Lab
Issuer       : CN=demo-EASTROOTCA-CA, DC=demo, DC=lab
Subject      : CN=*.demo.lab, OU=Information Technology, O=SolarWinds Demo Lab, L=Austin, S=TX, C=US
Thumbprint   : 039828B433E38117B85E3E9C1FBFD5C1A1189C91
NotBefore    : 3/30/2018 4:37:41 PM
NotAfter     : 3/30/2020 4:47:41 PM

Antivirus Exclusions

How about your antivirus exclusions? I’m sure you really, really want to know if those change.

$WindowsDefenderDetails = Get-MpPreference

$WindowsDefenderExclusions = $WindowsDefenderDetails.ExclusionPath

$WindowsDefenderExclusions | Sort-Object

Now you’ll know if something is added to or removed from the antivirus exclusion list.

C:\inetpub\SolarWinds
C:\Program Files (x86)\Common Files\SolarWinds
C:\Program Files (x86)\SolarWinds
C:\ProgramData\SolarWinds
C:\ProgramData\SolarWindsAgentInstall

Trying to find this out by hand would be tedious, so let’s just have SCM do the work for you.

This is all just a sample of the power of PowerShell and SCM. We’d love to know what you’ve got in mind for your environment. So, download a trial or upgrade to the latest version of SCM. Be sure to share your excellent scripting adventure so the rest of us can join in the fun!

  • OH BOY, im really glad i downloaded this module, now to brush up on some 'PS' i love you emoticons_happy.png

  • Ah - syntax.  If you are just copying and pasting into a PowerShell window, then we need to move the curly braces on the line after the "ForEach ( $this in $that )" to the end of that line instead of on the next line.

    <# Get the option for each scope: #>

    $Scopes = Get-DhcpServerv4Scope

    $ScopeOptions = @()

    ForEach ( $Scope in $Scopes ) {

       # Write-Host "Processing Scope: $( $Scope.ScopeId ) [$( $Scope.Name )]"

       $Options = $Scope | Get-DhcpServerv4OptionValue | Sort-Object OptionId

       ForEach ( $Option in $Options ) {

          # Write-Host "`tProcessing Scope: $( $Option.Name ) [$( $Option.value )]"

          $ScopeOptions += New-Object -TypeName PSObject -Property @{ "ScopeID"     = $Scope.ScopeID;

                                                                      "OptionID"    = $Option.OptionID;

                                                                      "OptionName"  = $Option.Name;

                                                                      "OptionType"  = $Option.Type;

                                                                      "OptionValue" = $Option.Value }

       }

    }

    $ScopeOptions | Select-Object -Property ScopeID, OptionID, OptionName, OptionType, OptionValue

  • At line:1 char:30

    + ForEach ( $Scope in $Scopes )

    +                              ~

    Missing statement body in foreach loop.

        + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException

        + FullyQualifiedErrorId : MissingForeachStatement

Thwack - Symbolize TM, R, and C