Professional PowerShell environments
Ready for Greatness
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
try{ 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
(incl. VAT)