Lead Image © lightwise, 123RF.com

Lead Image © lightwise, 123RF.com

Professional PowerShell environments

Ready for Greatness

Article from ADMIN 45/2018
The stability, portability, and scalability of PowerShell scripts is becoming increasingly important as automation scripts start to resemble mission-critical apps.

The time of self-written helpers for administrators has been over since Exchange Server 2010 and other PowerShell-dependent servers. For the long-term use of PowerShell (PS), documentation with comment-based help is mandatory.

Additionally, naming conventions for functions with verb-noun and company-specific prefixes would make it conceivable to specify a namespace such as get-DU_Freespace . For variable names, "Hungarian notation" is assumed to be the default. In addition to the standardization of documentation, clear script structures, and name concepts, error handling is also an expression of enterprise scripting.

The stability of a script application starts with the source code. Explicit exception handling should be introduced in each PS script with

> ErrorActionPreference = "stop"

Only then does the interpreter's distinction between terminating errors and non-terminating errors no longer matter. Now, every action can – and should – be wrapped with a try{} block, and possible exceptions can be handled with {catch}. In particular, you should not attempt to include external functions without error handling.

The code fragment in Listing 1 contains two actions if the integration fails. An error log should always be filled with data, including the specification of the error and date, and with an exit code in the event of an exit. This can be evaluated with the $LastExitCode environment variable and should be standardized.

Listing 1

Error Handling

   Update-UD_Content -StrInputFile $Str-MONINI -OldChar ";" -NewChar ",";
   catch {
     $StrMessage = $_.Exception.Message
     $IntLine = $_.InvocationInfo.ScriptLine-Number
     add-Content -Path ($StrErrorLogBaseDir + "\" + $StrScriptName_No_Ext + "_" + $StrNormalizedDate + ".txt") -value "error in Update-UD_Content at $(getdate): $StrMessage-$IntLine" -force; exit 10;

PS Cron Job

Creating a cron job is easy, whether in a GUI, with PS, or with the schtasks console application, as in this example:

> schtasks /CREATE /TN DISCHECK /TR "PowerShell.exe -noprofile -executionpolicy Unrestricted -file \\storage\data\scriptdischeck.ps1" /IT /SC MINUTE

The first intuitive approach – to run the scheduled job every minute and, if the process is already active, to prevent execution – also has a problematic component: Return values can be suppressed with the -noInteractive parameter; otherwise, output to stdout would certainly be bad. What can't be intercepted is the possibility that a process will no longer respond.

Scripts as a Service

A service is easier to maintain as a container. A number of interfaces, both in PS and Windows Management Instrumentation (WMI), check the status of a service – and not just whether it is running or stopped, but whether the "health" of the specific service can be output. The command

> gwmi win32_service | ? {$_.name -eq "winrm"} | select status,state

shows that the "winrm" service is fine and running. Creating a service is not as easy as creating a cron job. If you see PS for what it is (i.e., a .NET application for administrative purposes), you are already very close to the solution. High-level languages such as C# can create a service and host PS:

1. Start Visual Studio and select Windows Service as the project.

2. Create a runspace with the System.Management.Automation.Runspaces namespace.

3. Create the payload (i.e., the source code).

4. Install the service with installUtil.

However, the path from script to service can be shortened in some places. Tools such as nssm [1] allow you to install a service from the command line:

Start-Process -FilePath NSSMFolder\nssm.exe -ArgumentList 'install YourService "C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe" "-command "& { .D:\Scripts\discheck.ps1}"" ' -NoNewWindow -Wait

The PowerGUI editor offers the option to compile a script or create it directly as a service in the menubar under Tools. The alternative is based on the desire to be able to monitor and control all processes at any time, which, from the sequence of events developed above, is an illusion. As the script gets closer to the task, new accesses beyond return values occur. APIs like REST or .NET allow more effective script designs.

Dealing with Errors

An action that constantly checks for the consequences of an error is imperative. The control command is called permanently – whether it was necessary or not is decided in the follow-up. The alternative is to describe the state of a reaction. The benefits are obvious: The error case is described and documented. The subsequent actions can be created flexibly and are traceable. The cost of this architecture is a small background process waiting for its time to act. With

> SELECT * FROM __InstanceModiFicationEvent WITHIN 5 WHERE TargetInstance ISA "Win32_Service" AND Target Instance.State="Stopped"

such events could be handled. It is now conceivable to restart the service and write it into the event log.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs

Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.