1

I have a bunch of PowerShell scripts that are kicked off via scheduled tasks at various times.

The script are run multiple times with different arguments. Also administrators unfamiliar with scripting needed to be able to change the parameters without have to edit the code.

Due to this requirement, I passed the parameters in via arguments to powershell.exe in scheduled tasks. But this immediately became unwieldy, because now to change a script's parameters you have to go into task scheduler and edit the args to powershell.exe which now look like this (actually even longer):

-command "& 'C:\some\file\path\' -param1 'C:\some\file\path\' -param2 'C:\soawme\fawdile\pawawasth\' -param3 'C:\some\fisdfle\pasdfth\' -param4 'some arg'"

So now what I want to do is have each script just take in one editable configuration file where the parameters can be changed by the administrators. I could also organize the parameters more easily - have a "global" parameters configuration file all scripts use and then script-specific configuration files.

I thought I would use JSON in the configuration files and was thinking about doing something like this:

{
    "folder1":  [
                    "string",
                    "C:\\sldks\\dsf\\sdf\\sdf\\sd\\fsdf\\"
                ],
    "folder2":  [
                    "string",
                    "C:\\jiji\\sfef\\igig\\igg\\"
                ],
    "CSSFile":  [
                    "string",
                    "\\\\some\\netqwork\\path\\"
                ],
    "DBServer":  [
                     "string",
                     "myserver"
                 ],
    "DB":  [
               "string",
               "DB"
           ],
    "SqlQuery":  [
                     "string",
                     "SELECT * FROM myTable"
                 ],
    "UID":  [
                "string",
                "root"
            ],
    "PWD":  [
                "string",
                "123456"
            ]
}

$jsonObject = ConvertFrom-Json (cat $PathToMyExternalJsonFilePassedInFromTaskShedualer)

    function Set-ParamType ($jsonNode) {
        switch ($jsonNode[0])
        {
            'string' {return [string]$jsonNode[1]}
            'int' {return [int]$jsonNode[1]}
            'switch' {return [switch]$jsonNode[1]}
            default {"Debug: Unknown type"}
        }
    }

    $folder1  = Set-ParamType($jsonObject.folder1)
    $folder2  = Set-ParamType($jsonObject.folder2)
    $CSSFile  = Set-ParamType($jsonObject.CSSFile)
    $DBServer = Set-ParamType($jsonObject.DBServer)
    $DB       = Set-ParamType($jsonObject.DB)
    $SqlQuery = Set-ParamType($jsonObject.SqlQuery)
    $UID      = Set-ParamType($jsonObject.UID)
    $PWD      = Set-ParamType($jsonObject.PWD)

This way, in the scheduled task I have only one argument to pass in (the path of the configuration file). This seems to work, but I wanted to ask if there was a better and saner way to accomplish my goals. Is there something foolish about this approach I'm not seeing?

  • 1
    Is there something foolish about this approach I'm not seeing? Having admins "unfamiliar with scripting" change your script parameters seems pretty foolish to me, yes. – HopelessN00b Apr 30 '14 at 17:29
  • 1
    I use a batch file to wrap my powershell command when running in task scheduler. That way the script is separated from the parameters and I don't have to mess with the task scheduler (which is nice when it runs under a different user context. – uSlackr Apr 30 '14 at 18:59
  • The admins aren't scripting their entering parameters akin to "run a report on this server and put it here" more like an end user application. I thought about batch files too, but thought config files would be more manageable? This started as a few small scripts, but is growing into a framework for generating network reports. – red888 Apr 30 '14 at 19:15
  • I don't find that JSON particularly accessible, but you know your use case better than I. – uSlackr Apr 30 '14 at 19:42
  • I'll stick with what I'm doing for now and see if I run into problems. The only reason I'm using json is because I thought it would make extending parameters simpler as powershell 3.0 has a parser. Admittedly not as accessible as the familiar ini file format – red888 May 1 '14 at 13:05
2

What you're doing makes sense; no one need fiddle with the script (which may introduce code issues), or with the scheduled task (which may require that they know the "run as" account's credentials, and is also fiddly especially to those unfamiliar).

Having the configuration file path passed in as a parameter also makes sense; that way you can reuse your script with different configurations easily; so you're not restricted to a single "set of parameters" at any one time, but can have a set of parameters (configuration file) per scheduled task.

Possible Issue

Your JSON includes the data type; e.g."folder1": ["string","C:\\sldks\\dsf\\sdf\\sdf\\sd\\fsdf\\"]. Why? You'll have defined the types in your PS file anyway (if required); in your config you just want to hold the data without requiring that your admins know that "string" means "text" / without having to think about it. i.e. just have "folder1": "C:\\sldks\\dsf\\sdf\\sdf\\sd\\fsdf\\".

There are some additional considerations:

  • JSON vs XML vs INI vs Database vs Other. What sorts of files/technologies are your admins most familiar with / what do they find it easiest to manipulate? Personally I'd use XML for this; PS is just as comfortable with it, but the advantage is your admins can open it in a browser and immediately see whether it's valid XML or not (i.e. if they've missed a closing tag / misspelt something). That said, this depends very much on your team's abilities/preferences/tools.

  • Validation. What happens if someone enters bad data, or corrupts the file format (e.g. misses a bracket), or corrupts the file (e.g. saves in ANSI instead of UTF8 / whatever)? Make sure your script has something to handle this; and also consider how you'd find out; i.e. as well as "don't run if the config has issues" you want a "report an issue so that I can investigate & fix it if the config has issues".

  • Character Escaping. In the above example you'd had to escape your file path: C:\\sldks\\dsf\\sdf\\sdf\\sd\\fsdf\\ instead of C:\sldks\dsf\sdf\sdf\sd\fsdf\. Would admins know to do this / know which characters to escape for the config file's format? If you have a (generic) tool for editing such files which takes the pain out of this that'll save you some concerns; otherwise see point above on validation.

  • Security. Are the folders containing your scripts and your config files appropriately secured; otherwise people can manipulate your code to do what they like whilst running under the task's "run as" account. If the people editing config are different to those editing scripts it's likely best to keep them in separate directories to limit what each person can do.

Most of those things would still be considerations if passing parameters; so your way's definitely a step up regardless of the above considerations; but if you're looking to make something really friendly and robust, taking the above points into account will help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.