Fixing the Pipeline

Some comments to support Module 3 of course M10961

# The following command will not work as Get-ADComputer returns ADComputer

# objects which can not bind to any parameter of Get-Service

Get-ADComputer -Filter * | Get-Service -Name BITS

# One alternative is to use ForEach-Object but this tends to be processor intensive

Get-ADComputer -Filter * | ForEach-Object {Get-Service -Name BITS -ComputerName $_.name}

# Another option is to modify the object in the pipeline so it has the properties we need

Get-ADComputer -Filter * | Select *,@{Name=“ComputerName”;Expression={$_.name}} | Get-Service -Name BITS

# Or you can use parathentical commands

Get-Service -Name BITS -ComputerName (Get-ADComputer -Filter * | Select -ExpandProperty Name)

 

 

Creating PowerShell Custom Objects

Whilst rarely needed when running PowerShell commands in the console, creating custom objects can be a useful technique when writing scripts or functions.  The typical use of custom objects is where you want to retrieve information from multiple sources and combine it for manipulation or display purposes.

There are several different ways that we can go about creating custom objects.  These include:

  • Abusing an existing object
  • Creating a PSCustom object
  • Creating a PSCustom object from a hash table
  • Build your own .NET class (PowerShell 5.0)

Abusing an Existing Object

The –Property parameter of Select-Object will allow you select the properties of an object to be used subsequently in the pipeline.  One use of this is to return fewer properties than were previously used, but if you specify a name of a property that does not exist, Select-Object will actually add a property with that name to the object.  String objects have few existing properties, so are a good choice for creating a custom object, an empty string probably being the best bet. Continue reading Creating PowerShell Custom Objects

Datacenter Switchover – Updating DNS

As part of a Datacenter switchover, the DNS record of the CAS array in the failed site should be updated to the IP address CAS Array (or server) in the new site.  This will allow AutoDiscover to continue to continue to return the same fqnd of  the RPCClientAccessServer but have it resolve to a different IP address.

As most organisations will script the other steps necessary for a Datacenter switchover it makes sense to script this DNS change too.  This can be done with the Get-WMIObject cmdlet (alias GWMI).  Generally when people use the Get-WMIObject they access classes from the “Root\CIMv2” namespace.  As this is so common it is the default namesapce for Get-WMIObject so generally the -Namespace parameter is ommited.

To access DNS records we need to specify the “Root\MicrosoftDNS” namespace.  ‘A’ resource records can be accessed using the class “MICROSOFTDNS_ATYPE” and a filter can be used to only return the record we want for the CAS Array.

$a = Get-WmiObject -ComputerName DNS01.bret-tech.com 
 -namespace "root\microsoftdns"
 -class MICROSOFTDNS_ATYPE  
 -filter {OwnerName=CASArray.bret-tech.com} 

If the CAS Array has multiple IP addresses then $a will contain more than one object and ForEach will be required to loop through them individually, however as a CAS Array represents a shared IP address there should only be one IP
address.

To change the DNS record we can call the Modify method on this returned object.  This method requires two parameters:  the first the Time to Live or TTL of the record, setting this to $null creates a static entry, the second parameter is the IP address as a string.

$a.modify ($null , "10.20.0.30")

Updating Email addresses programmatically

Recently I was asked the question: ‘Can you remove a mailbox from email address policies to stop the reply address changing, but still have additional email addresses added automatically?’  The answer to this is no, not using the standard admin tools, but you could write a script to do this.  Below is the script I wrote to prove the concept.

The key elements are:

1.  Identifying which mailboxes are not controlled with email address policies.

$Addresses = @(get-mailbox `
      -filter {EmailAddressPolicyEnabled -eq $false})

2.  Extracting the current email addresses and appending an additional one. (Generate-Address is a function I wrote in the script that generates the email address in the format specified by the user running the script).

$old= @($Mailbox.emailaddresses | foreach `
      {$_.ProxyAddressString});
$new= Generate-Address $af1 $af2 $mailbox;
$old+=$new;

3.  Setting the new list of email addresses back to the mailbox. Continue reading Updating Email addresses programmatically

Using a Hash Table to format data

When you use Format-Table you can choose which columns you wish to view.

Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" | Format-Table DeviceID, FreeSpace, PercentFree

Instead of specifying just a property name you can use a Hash Table to have more control including:  What the Column header will be, calculating values to be shown and formatting the data.

Get-WMIObject Win32_LogicalDisk -Filter "DriveType=3" | Format-Table DeviceID, FreeSpace, @{Label = "Percent Free" ; Expression = {$_.FreeSpace / $_.Size}}

To control the data in the Hash Table we need to provide the following name/value pairs:

  • Label (or Name or n) / The text to be displayed in the column heading
  • Expression (or e) / The calculated value to be shown

Adding the Hash Table to the Format-Table command can lead to some long, hard to read commands.  One technique to tidy this up is to save the Hash Table as a variable first, and then to refer to the variable names in the Format-table command. Continue reading Using a Hash Table to format data

Open File Dialog Box

Often when working with PowerShell you will want to specify a file to read data from it.  Whilst the file path can be hard-coded into your script, or passed as a parameter it is often more convenient to take advantage of windows functionality that people have become used to.

The code below allows you to call one of the standard windows libraries to open the dialog box used for choosing files.  The code comes from a technet article which explains what each line of code does should you be interested.  The article can be found at Use a .NET Framework Class to Open a File Dialog Box

 

[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
$openFile = New-Object System.Windows.Forms.OpenFileDialog
$openFile.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" 
If($openFile.ShowDialog() -eq "OK") {get-content $openFile.FileName}

Creating you own GUI Application

PowerShell is a wonderful tool to gather information and analyse or display it. However, it can be somewhat daunting for the novice user to use. It is not unusual for tools and scripts to be written on behalf of less-technical staff, however basic scripts still require interaction from the command prompt.

One solution to this is to write a GUI front-end to your PowerShell code. Whilst PowerShell doesn’t have GUI commands provided natively as cmdlets, it is the scripting language for .NET so has access to all the .NET routines, including those needed to produce GUIs.

The process is simple enough, however a bit long-winded. The team at the Lync PowerShell blog have put together an easy to follow step-by-step guide of how to do this. This guide can be found here.

Changing Screen Colours

Changing screen colours can be easily done using the .NET [Console] object with commands similar to below:

[Console]::ForegroundColor = "yellow"
[Console]::BackgroundColor = "red"

After changing the background a Clear-Host  command should be issued.

To put the colours back to the default issue the following command:
[Console]::ResetColor()

Again, if you have previously changed the background colour and are reverting it you will need to run Clear-Host