PowerShell with a Purpose Blog

Securing Services with PowerShell

A reader, Paul, dropped me a note to ask about a script he'd written. He wanted to duplicate what had ben a manual process up to that point, including:

  1. Opening the Security Templates MMC snap-in
  2. Creating a template
  3. Expanding the "system services" node and double-clicking a service
  4. Defining the startup mode for that service as Disabled
  5. Editing the security (using the default of Admins, System having Full Control, and Interactive having Read)
  6. Repeating these steps for each service they needed to secure
  7. Saving the template
  8. Running the Security Configuration and Analysis MMC snap-in
  9. Creating a new Security Database using the saved template
  10. Applying the configuration to the computer.
No wonder he wanted to automate it! He decided to create a text file containing the equivalent of the security template, run SecEdit.exe to create the database, and SecEdit again to apply the template. Here's the PowerShell code:

# create database
$arguments = "/c secedit.exe /import /cfg " + $TemplateFile + " /db " + $TheDBFile + " /overwrite /quiet"
[diagnostics.process]::start("cmd.exe", $arguments).waitforexit() | Out-Null
sleep -Seconds 2
# apply template
$arguments = "/c secedit.exe /configure /cfg " + $TemplateFile + " /db " + $TheDBFile + " /overwrite /log " + $TheLogFile + " /quiet"
[diagnostics.process]::start("cmd.exe", $arguments).waitforexit() | Out-Null
sleep -Seconds 2

His question was, "is there a better way to do this?"

I don't think so. Obviously, Get-WmiObject, Invoke-WmiMethod, and the Win32_Service class' Change() method could be used to change the startup mode - but not to apply the permissions they're using. I think Paul's probably hit on exactly the right way to do this for his organization.

Granted, what Paul's doing isn't a "pure PowerShell" solution. But you know what? It doesn't matter. There are, as I like to say, no points for style in this business - only points for what works, and Paul's solution works. I'm sure there are other ways Paul could solve this problem - but I couldn't identify any that were markedly better. 

I've heard folks from Microsoft often asked, "why should I switch from ____ to PowerShell," and their usual answer is "don't." They didn't create PowerShell to force you to use it or switch from it; if you've got something else - a command-line tool in this case - that works, keep using it. PowerShell is designed to give you capabilities you didn't have before, in a more consistent and broad-reaching environment, but it isn't designed to necessarily replace anything you already have. In this example, Paul's using PowerShell to launch external command-line utilities, superbly illustrating the shell's ability to work with, and to integrate, existing tools and technologies. 

I might suggest some very minor syntactic improvements:

$arguments = "/c secedit.exe /configure /cfg $TemplateFile /db $TheDBFile  /overwrite /log $TheLogFile /quiet"
[diagnostics.process]::start("cmd.exe", $arguments).waitforexit() | Out-Null
sleep -Seconds 2

All I've done there is remove the string concatenation - in double quotes, PowerShell will replace a $variable with its contents, so you can avoid some of the ugliness of string concatenation. Paul, if you're reading this you'll have to double-check the syntax - the original you sent me in e-mail had is formatting a little whacked, so I may have missed a space or parameter. In addition, I might have used Start-Process instead of the static Start() method of the Process class; that cmdlet has a -wait parameter and I think you could accomplish everything you're after, here, using that cmdlet. Doing so would make the script a bit more readable for more folks. But again, these are minor syntactic points - and as I said, there are no points for style!
Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.