Unblocking Files with PowerShell v3

There are a number of new features in PowerShell v3 that while not huge like CIM or workflow are os significant help to the hard pressed administrator.  One of these is the Unblock-File cmdlet.

If you haven’t updated your help the online version is available at http://technet.microsoft.com/en-us/library/hh849924.aspx

To test it I downloaded the PowerShell v2 release notes from

http://www.microsoft.com/en-us/download/details.aspx?id=11539

 

The gives me a file

Windows Mangement Framework Release Notes en-US.rtf

 

When you download a file – internet explorer safety mechanisms kick in and the file is blocked. This prevents a number of things happening including running scripts

You can test if a file is blocked by right clicking the file and looking at its properties – it will have an Unblock button at the bottom right of the dialog.

You can also use PowerShell to do this.

First we need to identify the files that are blocked.  These are files with an Alternative Data Stream of “Zone.Identifier”

 

PS> Get-Item -Path "c:\test\Windows Mangement Framework Release Notes en-US.rtf" -Stream "Zone.Identifier"


   FileName: C:\test\Windows Mangement Framework Release Notes en-US.rtf

Stream                   Length
------                   ------
Zone.Identifier              26

 

If you try to test multiple files

Get-Item -Path c:\test\*.* -Stream "Zone.Identifier"

be prepared for lots of error messages when the system doesn’t find an alternative data stream.  Better still control the error messages

Get-Item -Path c:\test\*.* -Stream "Zone.Identifier" -ErrorAction SilentlyContinue

  FileName: C:\test\indice_analitico.pdf

Stream                   Length
------                   ------
Zone.Identifier              26


   FileName: C:\test\Windows Mangement Framework Release Notes en-US.rtf

Stream                   Length
------                   ------
Zone.Identifier              26

Now I don’t recognise that pdf file so I’ll leave that for later

Either of these will filter on the extension

Get-Item -Path c:\test\*.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue
Get-Item -Path c:\test\*.* -Filter *.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue

Once you have the file

Get-Item -Path c:\test\*.* -Filter *.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue | Unblock-File

won’t work because only the –LiteralPath parameter of Unblock-File takes pipeline input and that’s by property name

 

These two options will work

Get-Item -Path c:\test\*.* -Filter *.rtf -Stream "Zone.Identifier" -ErrorAction SilentlyContinue |
foreach {Unblock-File -Path $_.FileName }

 

Get-ChildItem -Path c:\test\*.* -Filter *.rtf | Unblock-File

 

I prefer the first because it allows me to test and then modify to perform the unblock.

Posted by RichardSiddaway | with no comments

WMI providers

I found a class new to me - Msft_Providers and this got me interested in WMI providers.

PS> Get-CimInstance -Class Msft_Providers | select -ExpandProperty provider
Msft_ProviderSubSystem
SCM Event Provider
WmiPerfClass

 

That seems a bit low. Digging a bit more I got back to the old favourite __provider.

Get-CimInstance -Class __provider | Measure-Object

produces an answer of 43 – not quite the answer to life, the universe and everything but close.

Is there any overlap between the two groups of providers?

$providers = Get-CimInstance -Class Msft_Providers | select -ExpandProperty provider           
Get-CimInstance -Class __provider | where Name -in $providers | select Name

 

provides the answer

Msft_ProviderSubSystem  

SCM Event Provider

 

In case you were wondering – “Starting with Windows Vista, the WMIPerfClass Provider and the WMIPerfInst Provider dynamically provide performance counter data for the WMI Performance Counter Classes.”

see http://msdn.microsoft.com/en-us/library/windows/desktop/aa392740(v=vs.85).aspx

 

One interesting property is the Hosting Model

Get-CimInstance -Class __provider | select HostingModel -Unique

Decoupled:NonCOM
NetworkServiceHost
WmiCore
LocalSystemHost
LocalServiceHost

NetworkServiceHost:[ReliabilityMetricsProvider]

 

But what do these mean

Full explanations for these and the other hosting models can be found at

http://msdn.microsoft.com/en-us/library/aa392509(VS.85).aspx

WmiCore - Activate provider in host to the WMI service. This hosting model is only supported for operating system components.

WmiCoreOrSelfHost - Activate provider in host to the WMI service or as local server. This hosting model is only supported for operating system components.

SelfHost - Activate provider as a local server implementation.

Decoupled:Com - Activate provider as a decoupled COM provider. See http://msdn.microsoft.com/en-us/library/aa390882(v=vs.85).aspx
 
Decoupled:NonCom - Activate provider as a non-COM event provider.
 
LocalSystemHost - Activate provider in the provider host process that is running under the LocalSystem account.

LocalSystemHostOrSelfHost - The provider is self-hosted or loaded into the Wmiprvse.exe process running under the LocalSystem account.

NetworkServiceHost - Activate provider in the provider host process that is running under the NetworkService account.

LocalServiceHost - Activate provider in the provider host process that is running under the LocalService account.

NetworkServiceHostOrSelfHost - The provider is self-hosted or loaded into the WmiPrvse.exe process running under the NetworkService account. NetworkServiceHostOrSelfHost is the default configuration when the HostingModel property in __Win32Provider is NULL. Because NetworkServiceHostOrSelfHost is the default, providers from earlier operating systems can continue to work in Windows Vista, Windows Server 2008, and later operating systems.

Get-CIMInstance is a new cmdlet in PowerShell v3. It is part of the new API for working with WMI. I will be blogging about these in greater detail over the next weeks and months as Powershell v3 is released.

More information on providers and the CIM cmdlets can be found in PowerShell and WMIwww.manning.com/powershellandwmi

Where-object in PowerShell v3

Where-Object – aliased to where, but never, ever, ever, ever to ? – had a very simple syntax in PowerShell v2

Where-Object [-FilterScript] <scriptblock> [-InputObject <psobject>] [<CommonParameters>]

It was normally used as

Get-Process | where {$_.CPU -gt 25}

The –FilterScript parameter (positional as 1 so don’t have to use it) supplies a script block that performs the filtering. In this case it looks at the current object on the pipeline (indicated by $_) and compares the CPU property to 25. If the property has a greater value it is passed.

Any of the comparison operators could be used in the filter block.

With PowerShell v3 it gets easier

Get-Process | where CPU -gt 25

We can just give the property name, the comparison operator and the value. 

This only works for a single property. You can’t do this

PS> Get-Process | where CPU -gt 25 -and Handles -gt 2000
Where-Object : Cannot bind parameter because parameter 'gt' is specified more than once. To provide multiple values to
parameters that can accept multiple values, use the array syntax. For example, "-parameter value1,value2,value3".
At line:1 char:45
+ Get-Process | where CPU -gt 25 -and Handles -gt 2000
+                                             ~~~
    + CategoryInfo          : InvalidArgument: (:) [Where-Object], ParameterBindingException
    + FullyQualifiedErrorId : ParameterAlreadyBound,Microsoft.PowerShell.Commands.WhereObjectCommand

You have to go back to

Get-Process | where {$_.CPU -gt 25 -and $_.Handles -gt 2000}

but hang on a minute the error message said that gt is a parameter!

If you look at the help file for where-object you will see lots of lines like this

Where-Object [-FilterScript] <ScriptBlock> [-InputObject <PSObject>] [<CommonParameters>]
  
Where-Object [-Property] <String> [[-Value] <Object>] [-EQ [<SwitchParameter>]] [-InputObject <PSObject>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Contains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -GE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -In [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CContains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CEQ [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CGE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CGT [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CIn [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CLE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CLike [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CLT [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CMatch [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotContains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotIn [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotLike [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -CNotMatch [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Is [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -IsNot [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -LE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Like [<SwitchParameter>] <CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -LT [<SwitchParameter>] <CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -Match [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NE [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotContains [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotIn [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotLike [<SwitchParameter>] [<CommonParameters>]
   
Where-Object [-Property] <String> [[-Value] <Object>] [-InputObject <PSObject>] -NotMatch [<SwitchParameter>] [<CommonParameters>]

The first option is the PowerShell v2 version. 

Notice that the comparison operators are switch parameters and each is in a different parameter set – thats why you can’t have multiples

This is a very useful addition to where-object that simplifies syntax (we often only perform a single comparison in the filter) and reduces typing.

It still doesn’t change the fact that you should never, ever, ever, ever alias where-object to ?

Posted by RichardSiddaway | with no comments
Filed under:

UK PowerShell group–next two meetings

29 May 2012

PowerShell and Windows server 2012 – new functionality pt 2

http://msmvps.com/blogs/richardsiddaway/archive/2012/05/08/uk-powershell-group-may-2012.aspx

 

4 July

Jonathan Medd

XenDesktop and PowerShell

This will be at the slightly later time of 8.30 BST.  Details to follow

Posted by RichardSiddaway | with no comments

Using Invoke-WmiMethod to set the DNS servers

In the last post I showed that there was an issue with the way the SetDNSServerSearchOrder of the Win32_NetworkAdapterConfiguration class worked

This would work

$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=7"
$nic.SetDNSServerSearchOrder("10.10.54.201")

but using Invoke-WmiMethod failed

After discussions with Bartek Bielawski (PowerShell MVP) and a bit more digging I found that for multiple DNS servers this would work

$dnsserver = "10.10.54.201", "10.10.54.98"
Get-WmiObject -Class Win32_NetworkAdapterConfiguration  -Filter "Index=7" | Invoke-WmiMethod -Name SetDNSServerSearchOrder -ArgumentList (, $dnsserver)

Its necessary to create an array as the input argument  (, $variable) – its a unary array ie one element array

if you want to use just a single DNS server then you need to use the unary array trick twice – once when you create the variable and again when you use Invoke-wmimethod.  Messy but it works

$dnsserver = (,"10.10.54.201")
Get-WmiObject -Class Win32_NetworkAdapterConfiguration  -Filter "Index=7" | Invoke-WmiMethod -Name SetDNSServerSearchOrder -ArgumentList (, $dnsserver)

 

If you want to use the new CIM cmdlets in PowerShell v3 – its easy if you have multiple DNS servers

$dnsserver = "10.10.54.201", "10.10.54.98"
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=7" | Invoke-CimMethod -MethodName SetDNSServerSearchOrder -Arguments @{DNSServerSearchOrder = $dnsserver}

 

for a single one we just need to create a unary array on the Arguments parameter
$dnsserver = "10.10.54.201"
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=7" | Invoke-CimMethod -MethodName SetDNSServerSearchOrder -Arguments @{DNSServerSearchOrder = (,$dnsserver)}

 

This is not satisfactory because we have to adopt different techniques depending on the number of DNS servers we need to put into NIC property. This is NOT a PowerShell issue – it has to be a WMI issue because the IP address that we saw last time also takes an array and it was very happy with a single value.

Hopefully this is not something that will come up too often but be aware of these options when working with WMI methods

TCP/IP Alternative Configurations: pt IV reset to static address

At some stage we may need to reset our NIC back to having a static address

$index = 7            
            
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration `
-Filter "Index=$index"             
            
$ipaddress = @("10.10.54.202")            
$subnet = @("255.255.255.0")            
Invoke-WmiMethod -InputObject $nic -Name EnableStatic -ArgumentList $ipaddress, $subnet            
            
$dnsserver = "10.10.54.201"            
$nic.SetDNSServerSearchOrder($dnsserver)            
            
#Invoke-WmiMethod -InputObject $nic -Name SetDNSServerSearchOrder -ArgumentList $dnsserver

We get the configuration of the NIC and use the EnableStatic method to set the address and subnet

The SetDNSServerSearchOrder method is used to set the DNS server.

Notice I haven’t been able to use Invoke-WmiMethod at this point – I’ve had to call the method directly on the object. There appears to be an issue with the formatting of the DNS server addresses as Invoke-WmiMethod complains that the argument has to be an array.

This is under investigation.

More on using WMI with PowerShell can be found in PowerShell and WMI. Chapter 11 covers network adapters in detail.  More details from www.manning.com/powershellandwmi

Posted by RichardSiddaway | with no comments

TCP/IP Alternative Configurations: pt III set the alternative configuration

 

We have seen how to set the NIC to use DHCP to get its address. This post shows how to set the alternative configuration on the NIC. If you just  want APIPA then do nothing – other wise use this script

$HKLM = 2147483650 #HKEY_LOCAL_MACHINE            
            
$index = 7            
$nic = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index=$index"            
            
$key = "SYSTEM\CurrentControlSet\services\Tcpip\Parameters\Interfaces\$($nic.SettingID)"            
            
Invoke-WmiMethod -Class StdRegprov -Name SetDWORDvalue -ArgumentList $hklm, $key, "AddressType", 2            
            
Invoke-WmiMethod -Class StdRegprov -Name SetMULTISTRINGvalue -ArgumentList $hklm, $key, "Alternate_$($nic.SettingID)", "ActiveConfigurations"            
Invoke-WmiMethod -Class StdRegprov -Name SetSTRINGvalue -ArgumentList $hklm, $key, "10.10.54.202", "DhcpIpAddress"            
Invoke-WmiMethod -Class StdRegprov -Name SetSTRINGvalue -ArgumentList $hklm, $key, "10.10.54.201", "DhcpNameServer"            
Invoke-WmiMethod -Class StdRegprov -Name SetSTRINGvalue -ArgumentList $hklm, $key, "255.255.255.0", "DhcpSubnetMask"

Again I’m cheating by defining the NIC in terms of its Index number

The registry key is derived from the SettingID property of the NIC

We then need to set a number of registry values. The AddressType sets the alternative configuration to use our informations rather than APIPA. The ActiveCinfigurations value is set using the SettingID property of the NIC

The address, subnetmask, and names server are set.

If you look carefully at the lines where we use the SetMULTISTRINGvalue and SetSTRINGvalue methods you will notice that we give the hive, key, value and then registry value name  whereas the SetDWORDvalue method we give hive, key, value name and then value.

This is a quirk of Invoke-WmiMethod

The WMI documentation for SetMULTISTRINGvalue and SetSTRINGvalue methods state the parameters should be:

  • hive
  • registry key
  • registry value name
  • value

This order is constant across the Set* methods of the StdRegProv class -  see http://msdn.microsoft.com/en-us/library/windows/desktop/aa393600(v=vs.85).aspx

If we do some investigation

PS> ([wmiclass]"StdRegprov").GetMethodParameters('SetSTRINGvalue')


__GENUS          : 2
__CLASS          : __PARAMETERS
__SUPERCLASS     :
__DYNASTY        : __PARAMETERS
__RELPATH        :
__PROPERTY_COUNT : 4
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
hDefKey          : 2147483650
sSubKeyName      :
sValue           : hello
sValueName       :

This clearly shows we need to give the value before the value name.

the same holds true if we investigate using Get-CimClass in PowerShell v3

Get-CimClass -ClassName StdRegProv |
select -ExpandProperty CimClassMethods |
where Name -eq "SetStringValue" |
select -ExpandProperty Parameters

produces

Name                                         CimType Qualifiers
----                                         ------- ----------
hDefKey                                      UInt32 {ID, IN}
sSubKeyName                                  String {ID, IN}
sValue                                       String {ID, in}
sValueName                                   String {ID, in}

if we use Invoke-CimMethod its not to much of a problem as we have to provide the value name and value pairs as a hash table we are not relying on argument order.

I’ll post an alternative listing using the CIM cmdlets another time

Advanced PowerShell v3 book

Three new chapters are added to the MEAP – Manning Early Access Program

Chapter 3 – Using the PowerShell help system – includes PowerShell v3 Updateable help

Chapter 5 – Working with PSsnapins and Modules

Chapter 9 – Formatting

 

www.manning.com/powershellindepth

Posted by RichardSiddaway | with no comments
Filed under: ,

1 millionth hit

This blog had its 1 millionth hit yesterday.  Thank you to everyone who takes the time to read my posts

Posted by RichardSiddaway | 2 comment(s)
Filed under:

Scripting Games 2012 comments: #20 multiple ifs

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

Posted by RichardSiddaway | with no comments

TCP/IP Alternative Configuration: pt II Set DHCP

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

Scripting Games 2012 comments: #19 default parameters

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.

Scripting Games 2012 comments: #18 computer names

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

Test-Connection on PowerShell v3

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

Test-Connection oddities

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

Posted by RichardSiddaway | with no comments
Filed under:

Scripting Games 2012 comments: #17 opening a csv file

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.

Scripting Games 2012 comments: #16 reading environmental variables

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.

Posted by RichardSiddaway | with no comments
Filed under:

TCP/IP Alternative Configuration: pt I The configuration

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

Posted by RichardSiddaway | with no comments

PowerShell User Group Recodings

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 my 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

Posted by RichardSiddaway | with no comments

Scripting Games 2012 comments: #15 pipelines

There are a few comments to make about using the pipeline but one of the obvious issues I saw from the games was this type of approach

 

$p = Get-Process
$p | where {$_.Name -like "powershell*"}

 

The only time this is valid is if you need to access exactly the same data later in your script.

In all other cases use

Get-Process | where {$_.Name -like "powershell*"}

 

if you want to split the lines to make it more readable the pipe symbol acts as a line continuation character so

Get-Process |
where {$_.Name -like "powershell*"}

is just as valid

PowerShell is all about the pipeline – use it to your advantage

More Posts Next page »