Simple PowerShell introduction for Windows Server administration, automation and scripting

Reading Time: 17 Minutes

Windows PowerShell (“PS” for short) is an important tool in Windows Server for administrators. You can use PowerShell for Windows Server administration, software installation, automation, and shell/command-line scripting. Here is a small and simple introduction to Windows PowerShell.

About PowerShell

Windows PowerShell is Microsoft’s scripting language of choice. Windows PowerShell is a task-based command-line shell and scripting language designed especially for system administration. Built on the Microsoft .NET Framework, Windows PowerShell helps IT professionals and power users control and automate the administration of the Windows operating system and applications that run on Windows.

An advantage of PowerShell is the ability to execute ordinary Windows binaries. You can execute Windows commands from within PowerShell, no matter whether it is appcmd, dir, forfiles, or advanced netsh commands.

Because it’s built on the .NET Framework, you can even use .NET functions and functionality. For example to make an SMTP connection:

(New-Object System.Net.Sockets.TcpClient).Connect( "smtp.example.com", "25" )

Built-in Windows PowerShell commands are called cmdlets. They let you manage the computers in your enterprise from the command line. Windows PowerShell providers let you access data stores, such as the registry and certificate store, as easily as you access the file system. In addition, Windows PowerShell has a rich expression parser and a fully-developed scripting language.

Cmdlets

A cmdlet is a lightweight command that is used in the Windows PowerShell environment. The Windows PowerShell runtime invokes these cmdlets within the context of automation scripts that are provided at the command-line. The Windows PowerShell runtime also invokes them programmatically through Windows PowerShell APIs.

The Get-WMiObject Cmdlet – Retrieving Data Using WMI

In scripts you often see the use of Get-WMiObject cmdlet. WMI stands for Windows Management Instrumentation. You may wonder why there is so much WMI usage in PowerShell, Microsoft explains:

At this point in time there are only a few cmdlets (Get-Process, Get-Service, and Get-EventLog) designed for carrying out system administration tasks. Because of that, WMI remains the primary automation technology for system administration, so system administrators will likely rely heavily on Get-WmiObject to help them with their routine management tasks.

And there’s an added bonus, too: unlike most cmdlets, Get-WmiObject can be run against remote computers. That means you really can use Windows PowerShell as a management tool.

By default, Get-WmiObject binds to the root\cimv2 namespace on the local computer, making it extremely easy to return property values for any class found in cimv2.

As you can see, for Windows administration with PowerShell, a basic understanding of WMI is required.

Scripting in Windows PowerShell

One task you can use Windows PowerShell for is scripting: automate your daily tasks using simple PowerShell scripts. One of such is, for example, a PS script to monitor Windows services like LanmanWorkstation. Another to find all files owned by a particular user. These two examples should provide some insights in the earlier mentioned cmdlet usage in PS. As said, you can also combine PowerShell with your normal Windows commands in one script.

Command-line arguments in PS

A PS script can accept command-line arguments. Imagine an unattended installation script to automate the installation of components of your web server. For example an script to install PHP. Now, if you want to add an option to either update or install PHP, as a command-line argument, add the following at the top of your PS script (different styles and options for adding command-line arguments support are possible):

# initialization
$mode      = $args[0]
$arguments = @{
  "-i" = "install PHP";
  "-u" = "update PHP";
  "-v" = "PHP version information";
}

# ...
# ...

$map = $args[1]
if ( $mode -and $arguments.ContainsKey( $mode ) ) {

  # we've added a php-version.txt file containing 
  # PHP's version number, e.g 7.0.5
  if ( ( test-path php-version.txt ) ) {
    $version = get-content php-version.txt
  }
  set-variable -name versie -value $version -scope script

  if ( ( $mode -eq "-i" ) ) {
    install ( $version )
  }

  if ( ( $mode -eq "-u" ) ) {
    update ( $version , 0 )
  }

  if ( ( $mode -eq "-v" ) ) {
    $return = version ( 1 )
  }
}

else {
  write-host "[i] Usage:"
  foreach ( $s in $arguments.Keys ) {
    write-host "[i]  $s " $arguments[$s]
  }
}

Now when you call your script install-php.ps1 with a command-line argument -i, the install function is executed, installing PHP. Want to know the current installed PHP version? Let’s have a look at the version function:

function version ( $returnerror ) {
  if ( test-path $target\php-version.txt ) {

    # open $target\php-version.txt containing 
    # the version number
    $found = get-content $target\php-version.txt
    write-host "[*] Version information for $target"
    write-host "[i] $found"
    return $found
  }

  else {
    if ( $returnerror ) {
      write-host "[E] Error: PHP is not installed!"
    }
    return 0
  }
}

As you can see, adding command-line arguments support into your PowerShell scripts may make your script library easier to understand. Now we have one PowerShell script for the installation of PHP, to update PHP and to look up its version. Otherwise that would have been three separate scripts.

Interesting:   PHP with WinCache on IIS

You can easily do the same when installing Windows Server features:

# Accept a $feature argument to install an specific 
# Windows Server feature
param (
  [string]$feature = $(throw "-feature is required.")
 )

Add-WindowsFeature `
  -Name $feature `
  -Source \path\to\windows\2012r2\sources\sxs

If … Else, If … ElseIf … Else logic

Flow control with If, ElseIf and Else in Windows PowerShell. Using If, ElseIf, Else you decide what a script has to do at a certain point, when a condition is met. An If is often used in an evaluation or comparison, e.g If $foo = bar, do this, Else do something else… He, that’s logic! :-)

Let’s have a look at the following example:

# If .. ElseIf .. ElseIf .. Else .. in PowerShell
param (
  [string]$a = $( throw "please provide a number 1 .. 6" )
)

If ( $a -eq "1" ) {
  write-host "Your number of choice: 1"
}
ElseIf ( $a -eq "2" ) {
  write-host "Your number of choice: 2"
}
ElseIf ( $a -eq "3" ) {
  write-host "Your number of choice: 3"
}
ElseIf ( $a -eq "4" ) {
  write-host "Your number of choice: 4"
}
ElseIf ( $a -eq "5" ) {
  write-host "Your number of choice: 5"
}
ElseIf ( $a -eq "6" ) {
  write-host "Your number of choice: 6"
}
Else {
  write-host "Can't read?! I asked for a number between 1 and 6!"
}

Playing with this, the output is:

PS C:\Users\jan> .\Desktop\if-else.ps1
please provide a number 1 .. 6
At C:\Users\jan\scripts\if-else.ps1:3 char:18
+   [string]$a = $( throw "please provide a number 1 .. 6" )
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (please provide a number 1 .. 6:String) [], RuntimeException
    + FullyQualifiedErrorId : please provide a number 1 .. 6

PS C:\Users\jan> .\scripts\if-else.ps1 1
Your number of choice: 1
PS C:\Users\jan> .\scripts\if-else.ps1 3
Your number of choice: 3
PS C:\Users\jan> .\scripts\if-else.ps1 5
Your number of choice: 5
PS C:\Users\jan> .\scripts\if-else.ps1 6
Your number of choice: 6
PS C:\Users\jan> .\scripts\if-else.ps1 9
Can't read?! I asked for a number between 1 and 6!
PS C:\Users\jan>

Not very hard, but you can imagine a script like this can get very long and difficult to read.

PowerShell Switch statement

The switch statement in PowerShell enables you to write a script that can choose from a series of options, but without requiring you to write a long series of if statements. When having a large If ( ) {.. } ElseIf ( ) {.. } ElseIf ( ) {.. } Else {.. } block in your scripts, it’s often better to rewrite those to a Switch statement. Not only makes this your PowerShell script execute faster (switch often is), it makes your script easier to read as well. Let’s rewrite the above If .. ElseIf .. ElseIf .. Else .. logic.

# Switch statement in PowerShell
param (
  [string]$a = $( throw "please provide a number 1 .. 6" )
)

switch ( $a ) {
  1 { "Your number of choice: 1" }
  2 { "Your number of choice: 2" }
  3 { "Your number of choice: 3" }
  4 { "Your number of choice: 4" }
  5 { "Your number of choice: 5" }
  6 { "Your number of choice: 6" }
  default { "Can't read?! I asked for a number between 1 and 8!" }
}

As you can see, the same script rewritten with a Switch in stead of If statement is much shorter and easier to read/understand. It outputs:

PS C:\Users\jan> .\scripts\switch.ps1
please provide a number 1 .. 6
At C:\Users\jan\scripts\switch.ps1:3 char:18
+   [string]$a = $( throw "please provide a number 1 .. 6" )
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (please provide a number 1 .. 6:String) [], RuntimeException
    + FullyQualifiedErrorId : please provide a number 1 .. 6

PS C:\Users\jan> .\scripts\switch.ps1 1
Your number of choice: 1
PS C:\Users\jan> .\scripts\switch.ps1 5
Your number of choice: 5
PS C:\Users\jan> .\scripts\switch.ps1 3
Your number of choice: 3
PS C:\Users\jan> .\scripts\switch.ps1 6
Your number of choice: 6
PS C:\Users\jan> .\scripts\switch.ps1 66
Can't read?! I asked for a number between 1 and 8!
PS C:\Users\jan>

PowerShell functions

A function in PowerShell is like a function in any other language, whether it’s C#, PHP, Bash. Within Powershell you can reference functions within statements. A function is basically a named block of code. When you call the function name, the script block within that function runs.

You can include any PowerShell statements within the script block, and you can add input parameters so you can use the same function in different situations. Let’s look at how to create functions, define input parameters, and work with functions in PowerShell scripts.

Create a PowerShell function
A PowerShell function must have a function name, to call it by, and a script block between curly brackets { } or braces. For example:

function HelloWorld {
  Write-Host "Hello World in PowerShell!"
}

As you can see, this function definition begins with the function keyword, followed by the function’s name: HelloWorld. The script block includes just one command, it echos the string “Hello World in PowerShell!”. When you create a function, PowerShell stores it in memory for the duration of your session. During that session, you can call the function at any time by simply entering the function’s name, as in HelloWorld. After pressing ENTER in the PowerShell shell, or from the point in your script, the function block is run and the output presented. In this case the above mentioned string, but it can be anything.

Interesting:   How to determine if a SQL Server backup is compressed?

Let’s add the function “HelloWorld” beneath the function, and execute it as a PS script. The script becomes:

function HelloWorld {
  Write-Host "Hello World in PowerShell!"
}

HelloWorld

And it’ll output:

PS C:\Users\jan> .\scripts\helloworld.ps1
Hello World in PowerShell!

Powershell functions also accept parameters:

function testFunction ($arg1, $arg2) {
  Write-Host $arg1
  Write-Host $arg2
}

There are pitfalls when calling function parameters though! In Calling Functions in PowerShell, Thomas Lee provides a succinct example of one pitfall that even experienced PowerShell scripters will occasionally tumble into-writing a basic function call that produces unexpected results.

Here is Michael Sorens’ version of that script, revised for clarity and exposition for the simple-talk.com article Down the Rabbit Hole- A Study in PowerShell Pipelines, Functions, and Parameters (blatantly copied here and adjusted a bit):

Function
function testFunction($a, $b, $c) {
    "`$a=$a"
    "`$b=$b"
    "`$c=$c"
}
Call
testFunction("Foo", "Bar", "foobar")
testFunction "Foo", "Bar", "foobar"
testFunction "Foo" "Bar" "foobar"
testFunction -c "foobar" -a "Foo" -b "Bar"
Result
testFunction("Foo", "Bar", "foobar")
$a=Foo Bar foobar
$b=
$c=
testFunction "Foo", "Bar", "foobar"
$a=Foo Bar foobar
$b=
$c=
testFunction "Foo" "Bar" "foobar"
$a=Foo
$b=Bar
$c=foobar
testFunction -c "foobar" -a "Foo" -b "Bar"
$a=Foo
$b=Bar
$c=foobar

Here you have one function testFunction, with different calls passing multiple parameters into a PowerShell function and different values.

PowerShell Comparison operators – compare values in PowerShell

PowerShell supports a number of comparison operators. The following operators are all case-insensitive by default:

PowerShell Comparison Operators
operator explanation
-eq Equal
-ne Not equal
-gt Greater than
-ge Greater than or equal
-lt Less than
-le Less than or equal
-Like Wildcard comparison
-NotLike Wildcard comparison
-Match Regular expression comparison
-NotMatch Regular expression comparison
-Contains Containment operator
-NotContains Containment operator
-In Like -contains, but with the operands reversed (PowerShell 3.0)
-NotIn Like -notcontains, but with the operands reversed (PowerShell 3.0)
-Replace Replace operator

By default, all comparison operators are case-insensitive. To make a comparison operator case-sensitive, precede the operator name with a “c“. For example, the case-sensitive version of “-eq” is “-ceq“. To make the case-insensitivity explicit, precede the operator with an “i“. For example, the explicitly case-insensitive version of “-eq” is “ieq“.

Run Update-Help and about_Comparison_Operators to view its help information.

Windows Server administration, installation and automation with PowerShell

Windows PowerShell provides a lot of Windows Server administration cmdlets. Cmdlets to use when installing Windows Server, or to automate the installation, and so on. There are just too many to mention them all. Some important ones – to me, in my daily routine – are:

  • Get-WmiObject
  • Get-Service, Stop-Service, Start-Service
  • Test-NetConnection (and because Windows PowerShell is built on .NET, you can also use (New-Object System.Net.Sockets.TcpClient).Connect("localhost", "25") in stead of Test-NetConnection -Port 25 -ComputerName localhost. See monitor Windows services with PowerShell for an example)
  • Get-FsrmQuota, Set-FsrmQuota
  • Get-ChildItem
  • Get-Acl
  • Install-WindowsFeature, Uninstall-WindowsFeature, Get-WindowsFeature
  • AppCmd (not a Cmdlet, but very handy to use within Windows PowerShell to create websites and application pools)
  • Get-website, Get-WebConfiguration, Get-WebConfigurationProperty (find more Web Server (IIS) Administration Cmdlets in Windows PowerShell on Technet)

Often, when there is a cmdlet starting with Get-, there is also one with Set-. In my daily routine, Set-FsrmQuota is as important to me as Get-FsrmQuota. The same goes for Get-Acl and Set-Acl, and so on.

Two example PS administration scripts:

find-all-PHP-handlers-matching-an-scriptProcessor-condition.ps1

Get-Website | % {
  $sitename = $_.name; Write-Host "[X] Processing $sitename ... ";
  Try {
    Get-WebConfiguration /system.webServer/handlers/* -Location $_.name | Where {
      $_.scriptProcessor -eq "d:\PHP\php56\php-cgi.exe"
    }
  }
  Catch { }
}

Get-Website | % {
  $sitename = $_.name;
    $handlers = Get-WebConfiguration /system.webServer/handlers/* -Location $sitename
    If ( $handlers.scriptProcessor -eq "d:\PHP\php70\php-cgi.exe" ) {
      Write-Host $sitename
    }
}

w3wp-uptime.ps1

Get-Process w3wp | % {
  $pid = $_.Id
  $wmiProc = Get-WmiObject Win32_Process -Filter "ProcessID = '$pid'"
  New-Object PSObject -Property @{
    CommandLine = $wmiProc.ComandLine
    StartTime = $_.StartTime
  }
}

(Code credits: Chris N on StackOverflow)

Conclusion

Windows PowerShell is powerfull, but unfortunately, PowerShell isn’t as powerful and interactive as a shell as GNU/Linux’s Bash is (in my opinion). However, you can still create very powerful PowerShell scripts to use in your daily Windows Server administration tasks. The number of available cmdlets for PowerShell is too large to mention them all here. This post showed you a small fraction of those cmdlets, and gave you some beginner insights in PowerShell usage.

5 Replies to “Simple PowerShell introduction for Windows Server administration, automation and scripting”

Hi! Join the discussion, leave a reply!