PowerShell for Windows Admins


May 17, 2012  1:04 PM

Scripting Games 2012 comments: #20 multiple ifs

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

An if statement is used to test a condition and if is true do one thing and do another if it is false. It can be written generically as

if (<condition>){ do stuff}
else {do other stuff}

Sometimes we need to test numerous alternatives. We could use multiple if statements, sometimes we have to nest them which can lead to code like this

Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |            
foreach {            
 if ($_.FreeSpace -gt 1tb){Write-Host "Over 1TB of disk space free"}            
 else {             
   if ($_.FreeSpace -ge 500gb){Write-Host "Over 500GB of disk space free"}            
   else {            
     if ($_.FreeSpace -ge 300gb){Write-Host "Over 300GB of disk space free"}            
     else {            
      if ($_.FreeSpace -ge 200gb){Write-Host "Over 300GB of disk space free"}            
      else {            
        if ($_.FreeSpace -ge 100gb){Write-Host "Over 100GB of disk space free"}            
        else {            
          Write-Host "Insufficient disk space"            
        }            
     }            
     }            
   }            
 }             
 }

That’s not fun to write and its even less fun to debug or change

The code can be simplified by using if – elseif – else

Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |            
foreach {            
 if ($_.FreeSpace -gt 1tb){Write-Host "Over 1TB of disk space free"}            
 elseif ($_.FreeSpace -ge 500gb){Write-Host "Over 500GB of disk space free"}            
 elseif ($_.FreeSpace -ge 300gb){Write-Host "Over 300GB of disk space free"}            
 elseif ($_.FreeSpace -ge 200gb){Write-Host "Over 300GB of disk space free"}            
 elseif ($_.FreeSpace -ge 100gb){Write-Host "Over 100GB of disk space free"}            
 else{Write-Host "Insufficient disk space"}            
 }

This much more compact and understandable. We can do a better job if we use a switch statement which is similar in concept to if-elseif-else

Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |            
foreach {            
 switch ($_.FreeSpace) {            
 {$_ -gt 1tb}   {Write-Host "Over 1TB of disk space free"; break}            
 {$_ -ge 500gb} {Write-Host "Over 500GB of disk space free"; break}            
 {$_ -ge 300gb} {Write-Host "Over 300GB of disk space free"; break}            
 {$_ -ge 200gb} {Write-Host "Over 300GB of disk space free"; break}            
 {$_ -ge 100gb} {Write-Host "Over 100GB of disk space free"; break}            
 default {Write-Host "Insufficient disk space"}            
 }            
 }

We select the object to test and use $_ as a placeholder. Each line in the switch statement is a single test. The default statement is for anything that doesn’t pass any of the preceding tests

One difference between the if statements and switch is that with the if statements as soon as a condition is true testing stops. With switch testing would continue through all tests – break is used to stop that

When you need to perform multiple tests consider using a switch statement – it is less typing and easier to debug

May 16, 2012  3:12 PM

TCP/IP Alternative Configuration: pt II Set DHCP

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The next step on our journey to an alternative configuration is setting the NIC to use DHCP

I will keep cheating for now and specify the NIC – on my machine I now it is the NIC whose Win32_NetworkAdapterConfiguration has an Index of 7

$index = 7            
Get-WmiObject -Class Win32_NetworkAdapterConfiguration `
-Filter "Index=$index" |            
Invoke-WmiMethod -Name EnableDHCP

This sets the IP address to be obtained automatically via DHCP BUT it doesn’t set the DNS server to be delivered via DHCP. The old static DNS entries are retained.

To resolve this we use the SetDNSServerSearchOrder method without any arguments

$index = 7            
            
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration `
-Filter "Index=$index"             
            
Invoke-WmiMethod -InputObject $nic -Name EnableDHCP            
Invoke-WmiMethod -InputObject $nic -Name SetDNSServerSearchOrder            
            

I’ve modified the script slightly so we create an object for the WMI class and then use that object as the InputObject on two calls to Invoke-WmiMethod

We could have just as easily used

$nic.EnableDHCP()

$nic.SetDNSServerSearchOrder()

Now that we have the NIC set to use DHCP we need to configure the Alternative Configuration

More information on working with network adapters can be found in PowerShell and WMIwww.manning.com/powershellandwmi


May 16, 2012  1:50 PM

Scripting Games 2012 comments: #19 default parameters

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I often saw scripts that did something like this

function test1 {            
 param (            
   [string]$computername            
 )            
            
if (!$computername){            
  $computername = $env:COMPUTERNAME            
}            
            
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername              
}

A function, or script, defines a parameter. The first thing the function does it test the value of the parameter and if it doesn’t exist it sets it to a default value.

No, no, no – you are making work for yourself. 

Get PowerShell to do the work for you

function test2 {            
 param (            
   [string]$computername = $env:COMPUTERNAME            
 )            
            
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername              
}

See the difference?

The parameter definition now contains a default value.  If you don’t specify the parameter and a value the default kicks in and the function works.

Cuts down typing and gets PowerShell to do the work.


May 15, 2012  3:26 PM

Scripting Games 2012 comments: #18 computer names

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I have mentioned computer names a few times. One oddity is accessing the local machine.

There are three options

  • dot  .
  • localhost
  • $env:COMPUTERNAME

There are a number of occasions when . and localhost fail.

For example

PS> Get-EventLog -List -ComputerName .

  Max(K) Retain OverflowAction        Entries Log
  —— —— ————–        ——- —
  20,480      0 OverwriteAsNeeded      21,647 Application
     512      7 OverwriteOlder              0 DemoMate
  20,480      0 OverwriteAsNeeded           0 HardwareEvents
     512      7 OverwriteOlder              0 Internet Explorer
  20,480      0 OverwriteAsNeeded           0 Key Management Service
   8,192      0 OverwriteAsNeeded          10 Media Center
     512      7 OverwriteOlder              0 MyNewLog
     128      0 OverwriteAsNeeded         364 OAlerts
  20,480      0 OverwriteAsNeeded           1 Scripts
                                              Security
  20,480      0 OverwriteAsNeeded      56,135 System
  15,360      0 OverwriteAsNeeded      10,918 Windows PowerShell

PS> Get-EventLog -List -ComputerName localhost
Get-EventLog : The network path was not found.
At line:1 char:13
+ Get-EventLog <<<<  -List -ComputerName localhost
    + CategoryInfo          : NotSpecified: (:) [Get-EventLog], IOException
    + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.GetEventLogCommand

PS> Get-EventLog -List -ComputerName ‘localhost’
Get-EventLog : The network path was not found.
At line:1 char:13
+ Get-EventLog <<<<  -List -ComputerName ‘localhost’
    + CategoryInfo          : NotSpecified: (:) [Get-EventLog], IOException
    + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.GetEventLogCommand

PS> Get-EventLog -List -ComputerName $env:COMPUTERNAME

  Max(K) Retain OverflowAction        Entries Log
  —— —— ————–        ——- —
  20,480      0 OverwriteAsNeeded      21,647 Application
     512      7 OverwriteOlder              0 DemoMate
  20,480      0 OverwriteAsNeeded           0 HardwareEvents
     512      7 OverwriteOlder              0 Internet Explorer
  20,480      0 OverwriteAsNeeded           0 Key Management Service
   8,192      0 OverwriteAsNeeded          10 Media Center
     512      7 OverwriteOlder              0 MyNewLog
     128      0 OverwriteAsNeeded         364 OAlerts
  20,480      0 OverwriteAsNeeded           1 Scripts
                                              Security
  20,480      0 OverwriteAsNeeded      56,135 System
  15,360      0 OverwriteAsNeeded      10,918 Windows PowerShell

Get-EventLog fails with localhost

I always recommend using $env:COMPUTERNAME


May 15, 2012  11:37 AM

Test-Connection on PowerShell v3

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Following on from the previous post I performed the same tests on PowerShell v3

The behaviour is the same except that

Test-Connection -ComputerName . -Count 4 –AsJob

now give the 4 pings when you receive the job information


May 14, 2012  3:23 PM

Test-Connection oddities

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I’ve playing around with Test-Connection because I wanted to set up a long running WMI based job and I thought that pinging a machine lots of times would be a good way to do it. Test-Connection uses the Win32-PingStatus class.

I started with this

PS> Test-Connection -ComputerName . -Count 4

Source        Destination     IPV4Address   IPV6Address  Bytes    Time(ms)
——        ———–     ———–   ———–  —–    ——–
RSLAPTOP01    localhost       127.0.0.1        ::1          32       0
RSLAPTOP01    localhost       127.0.0.1        ::1          32       0
RSLAPTOP01    localhost       127.0.0.1        ::1          32       0
RSLAPTOP01    localhost       127.0.0.1        ::1          32       0

Nothing special there.

I then tried this

PS> Test-Connection -ComputerName . -Count 4 -Quiet
False

Huh?

PS> Test-Connection -ComputerName localhost -Count 4 -Quiet
True

Odd

PS> Test-Connection -ComputerName $env:COMPUTERNAME -Count 4 -Quiet
True

Very odd – seems like “.” isn’t liked when running –Quiet.  Another good reason to avoid it

I then tried it as a job

PS> Test-Connection -ComputerName . -Count 4 -AsJob

Id       Name     State      HasMoreData   Location     Command
–       —-     —–      ———–   ——–     ——-
3        Job3     Running    False         .            Test-Connection

PS> Get-Job

Id       Name     State      HasMoreData   Location     Command
–       —-     —–      ———–   ——–     ——-
1        Job1     Completed  True          .            Test-Connection
3        Job3     Completed  True          .            Test-Connection

PS> Receive-Job -Id 3

Source   Destination  IPV4Address  IPV6Address  Bytes    Time(ms)
——   ———–  ———–  ———–  —–    ——–
RSLAPTOP01 localhost    127.0.0.1        ::1       32       0

Only one ping is returned instead of the 4 I was expecting.

Not major problems but something to remember


May 14, 2012  11:21 AM

Scripting Games 2012 comments: #17 opening a csv file

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Some of the events involved creating a CSV file. While it wasn’t explicitly asked that you opened the file many entrants chose to add that code to their scripts.

There were a number of options presented – most involving opening Excel and importing the CSV file.

There is a much quicker way

Invoke-Item -Path test.csv

Invoke-Item causes any file to open in the default application associated with that file.  This will work for Office documents, text files and anything else that you can double click on a get it to open in an application.

If you use Invoke-Item on a .ps1 file – it will open in notepad just as if you’d double clicked it.


May 13, 2012  11:25 AM

Scripting Games 2012 comments: #16 reading environmental variables

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Windows maintains a set of environmental variables. Some, but not all, can be seen via the env: PowerShell drive

Get-ChildItem -Path env:

You can also use WMI to see some of the variables

Get-WmiObject -Class Win32_Environment | ft Name, VariableValue –a

 

Now how do you read them in your scripts?

 

I noticed a lot of people doing this

$name = (Get-Item env:\Computername).Value

 

It works but its a bit long winded.  A better method is this

$name = $env:COMPUTERNAME

$env: is the environment provider surfaced as a namespace

You can also use this technique with other providers e.g.

PS> $variable:MaximumAliasCount
4096

It doesn’t work with all providers e.g. the registry.


May 13, 2012  10:34 AM

TCP/IP Alternative Configuration: pt I The configuration

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A question on the forum got me wondering about setting the Alternative Configuration on a TCP/IP properties of a network adapter. NICs are normally configured to either DHCP or a static address. If you use DHCP another tab “Alternative Configuration” appears on the IPv4 properties dialog. This can be set to APIPA (an address in the range 169.254.x.x/16 – ie DHCP failed) or a static address. DHCP will be tried first and if it fails the Alternative Configuration kicks in.

I had never seen anything on configuring this so started to dig.

It turns out that the information is held in the registry – big surprise! The data is a little difficult to track down

## http://technet.microsoft.com/en-us/library/bb457118.aspx            
$index = 7            
$HKLM = 2147483650 #HKEY_LOCAL_MACHINE            
$data = @{}            
            
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=$index"            
            
$key = "SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\$($nic.SettingID)"            
            
$rc = Invoke-WmiMethod -Class StdRegProv -Name EnumValues -ArgumentList $hklm, $key            
            
if ($rc.ReturnValue -eq 0) {            
              
  $num = $rc.Types.count -1            
              
  for ($i=0; $i -le $num; $i++){            
                 
     switch ($rc.Types[$i]) {            
       1 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetStringValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty sValue}            
       2 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetExpandedStringValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty sValue}            
       3 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetBinaryValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty uValue}            
       4 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetDWORDValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty uValue}            
       7 {$value = Invoke-WmiMethod -Class StdRegProv -Name GetMultiStringValue -ArgumentList $hklm, $key, $($rc.sNames[$i]) | select -ExpandProperty sValue}            
       default {Write-Warning "Could not process $($rc.sNames[$i]) - type $($rc.Types[$i])"}            
     }            
            
     $data += @{$($rc.sNames[$i]) = $value}            
            
                   
  }  ## end for            
              
}            
else {            
 Write-Error "WMI call to registry provider failed"            
}              
            
$data.GetEnumerator() | sort key

 

I’ve cheated for now and defined the NIC I’m interested in – Index =7 is my LAN connection.

I need to work with the HKLM hive so define the appropriate constant.

After getting the WMI object for the NIC – filter on Index I use the SettingID to define the registry key I need. The settingID looks like this – {01F4E3B7-5F1F-40BD-8252-DCC3331891C1}

The EnumValues method gives me the registry value names and types for that key. I can loop through them and call the appropriate method to read the registry value.

The data is output sorted by value name and looks like this

Name                           Value

—-                           —–

AddressType                    0

DefaultGateway                 
DefaultGatewayMetric           
DhcpConnForceBroadcastFlag     0

DhcpGatewayHardware            {192, 168, 1, 1…}

DhcpGatewayHardwareCount       1

DhcpInterfaceOptions           {6, 0, 0, 0…}

DhcpServer                     255.255.255.255

Domain                                   
EnableDeadGWDetect             1

EnableDHCP                     0

IPAddress                      10.10.54.202

IsServerNapAware               0

Lease                          0

LeaseObtainedTime              1336923004

LeaseTerminatesTime            2147483647

NameServer                     10.10.54.201

RegisterAdapterName            0   
RegistrationEnabled            1   
SubnetMask                     255.255.255.0

T1                             1336923004

T2                             1336923004

UseZeroBroadcast               0  

 

This shows we have a static address – the fact that IPAddress is set and that EnableDHCP=0

Next time we will look at enabling DHCP and then setting the alternative configuration


May 13, 2012  6:54 AM

PowerShell User Group Recodings

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A number of the recent UK PowerShell group sessions are available as recordings for download.  The slides and demo scripts are usually included in the download package. They can be downloaded from mu skydrive under the PowerShell User group folder.
https://skydrive.live.com/#cid=43CFA46A74CF3E96&id=43CFA46A74CF3E96%212469

The following sessions are available

2011 09 PowerShell remoting and end point customisation
2011 11 Whats new in PowerCLI 5
2011 12 Intro to WMI
2011 12 WSMAN_WMI_and_CIM
2012 January PowerShell v3 CTP 2 overview
2012 February PowerShell and SQL Server
2012 March CIM cmdlets
2012 April Powershell in Windows Server 8

This list will be updated periodically

Enjoy


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: