Category Archives: Scripting Games 2013

Learning Points From PowerShell Scripting Games Event #4

Event 4 for the PowerShell Scripting Games 2013 has closed, here are a few learning points I picked up on from entries submitted.

1) Random AD Users

The first part of this event is to work with 20 randomly selected users from Active Directory. Initial thoughts might be that this is pretty straightforward. If you use the Get-ADUser cmdlet from the AD module then you could do something like this:

Get-ADUser | Get-Random -Count 20

This might be OK for small testing environments, but could potentially have some performance issues in an AD with thousands of users. It doesn’t matter so much for this event really, but don’t forget to consider potential performance issues for the real world.

For instance, if you did have an AD environment that size you could restrict the amount of users returned with:

Get-ADUser -ResultSetSize 500 | Get-Random -Count 20

Also for this event you don’t need to bring back all of the properties of a user, just those you need to export to the report. Use of the Properties parameter would speed up the query in a large environment too.

Get-ADUser -ResultSetSize 500 -Properties Department,Title,LastLogonDate,PasswordLastSet,Enabled,LockedOut

 

2) Testing for additional commands

Since the AD team were slightly late to the party in terms of PowerShell and typically it was one of the first things people wanted to use PowerShell for, there are a number of different methods for accessing AD via PowerShell. You can use ADSI or .NET, the 3rd party set of cmdlets from Quest or since Windows 2008 R2 the Microsoft AD module.

In terms of this event, any of these approaches really is fine. However, I saw a few different approaches for how to test whether a snapin or module was potentially available for use, for instance checking if a cmdlet was present.

I would test it by checking if the snapin or module was installed on the system. Since Get-PSSnapin returns an error if the snapin doesn’t exist you might want to take two slightly different approaches depending on what you are working with.

try {

$PSSnapin = Get-PSSnapin Quest.Activeroles.ADManagement -Registered -ErrorAction Stop
 Add-PSSnapin Quest.Activeroles.ADManagement
}
catch {

"blah blah cloud"
}

or

if ($Module = Get-Module ActiveDirectory -ListAvailable){

 Import-Module ActiveDirectory
}
else {

"blah blah cloud"
}

 

Learning Points From PowerShell Scripting Games Event #3

Event 3 for the PowerShell Scripting Games 2013 has closed, here are a few learning points I picked up on from entries submitted.

1) Filter to the left

Some cmdlets in PowerShell have their own filtering capabilities, which can make queries of large data sets more efficient. However, not all cmdlets do have this capability and you will need to pipe the results to Where-Object instead. It’s always worth checking the help and examples for a cmdlet first to see the best way to filter and if it has an option to do so then use it!

I’ve seen quite a few entries do this

Get-WmiObject Win32_LogicalDisk -ComputerName "localhost" | Where {$_.DriveType -eq 3}

This will get you the right results, but better is to use the filter parameter of Get-WmiObject

Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3"

 

2) ConvertTo-Html: PreContent and PostContent Parameters

Quite a few entries made nice use of these parameters to add additional content to the HTML output generated. For instance you could add an h2 header before the <table> with PreContent

Get-WmiObject Win32_LogicalDisk -filter "DriveType=3" | Select-Object Name,Size | ConvertTo-Html -PreContent "<h2>Local Fixed Disk Report</h2>" | Out-File Report.html

Event3b

It’s possible to include PowerShell code as part of these parameters, so to fulfill one of the other requirements to place the date and time at the bottom of the report you could do something like this:

Get-WmiObject Win32_LogicalDisk -filter "DriveType=3" | Select-Object Name,Size | ConvertTo-Html -PreContent "<h2>Local Fixed Disk Report</h2>" -PostContent "<br><hr><p> $(Get-Date)" | Out-File Report.html

Event3c

Learning Points From PowerShell Scripting Games Event #2

Event 2 for the PowerShell Scripting Games 2013 has closed, here are a few learning points I picked up on from entries submitted.

1) Win32_Processor

This event is a bit of a sneaky one and if you haven’t been affected by the issue before then you may not know it. The particular issue I am referring to  here is that “The number of physical hyperthreading-enabled processors or the number of physical multicore processors is incorrectly reported in Windows Server 2003“. The issue is essentially this:

“Before you apply this hotfix, the WMI classes and the WMI properties exhibit the following behavior.

Win32_ComputerSystem

  • The NumberOfLogicalProcessors property is not available.
  • The NumberOfProcessors property returns the number of logical processors that are available on the system.

Win32_Processor

  • The number of Win32_Processor instances that are returned is equal to the number of logical processors that are available on the system.
  • The NumberOfCores property is not available.
  • The NumberOfLogicalProcessors property is not available.

After you apply this hotfix, the WMI classes and the WMI properties exhibit the following behavior.

Win32_ComputerSystem

  • The NumberOfProcessors property returns the number of physical processors that are available on the system.
  • The NumberOfLogicalProcessors property returns the number of logical processors that are available on the system.

Win32_Processor

  • The NumberOfLogicalProcessors property returns the number of logical processors on the current instance.
  • The NumberOfCores property returns the number of cores on the current instance.
  • The number of Win32_Processor instances that are returned is equal to the number of physical processors that are available on the system.

This tripped me up once when I received back inconsistent results from a large server estate where I was querying via WMI the number of processors per server. Luckily in that environment I was able to deploy the hotfix everywhere, but you might not be able to and potentially you may have further inconsistencies with Windows 2000 servers that can’t be fixed. This event contains a Windows 2000 server, so you may need to code around it.

The initial thought would be to check the OS version, but then you would have to detect if the hotfix was installed if it was a 2003 box – probably too much work. So what we could do is check for the NumberofCores property on a WMI query for Win32_Processor and if it doesn’t exist calculate the number of cores and sockets via other means. I haven’t tested this on Windows 2003 minus hotfix or 2000 yet, but you should be able to count the number of unique SocketDesignations returned to determine the number of sockets.

$Processors = Get-WmiObject Win32_Processor
if ($NoOfCores = $Processors.NumberOfCores){

$NoOfSockets = ($Processors | Measure-Object).Count
}
else {

$NoOfCores = 'N/A'
 $NoOfSockets = ($Processors | Select-Object SocketDesignation -Unique | Measure-Object).count
}

2) Using Add-Member when creating custom objects

Event 2 requires you to output results and it’s good to see many people doing this by creating their own objects to output. A number of entries use the Add-Member cmdlet to add properties to their custom object. While this is a perfectly valid way to do it and was the technically prescribed way  in PowerShell v1, I prefer a couple of different approaches and in this previous article explain why – mainly around performance. So I would do something like this (note that it does require PowerShell v3)

[pscustomobject] @{
 Name = $_.Name
 NoOfCores = $NoOfCores
 NoOfSockets = $NoOfSockets
#etc........
}

Hope this helps!

Learning Points From PowerShell Scripting Games Event #1

Event 1 for the PowerShell Scripting Games 2013 has closed, here are a few learning points I picked up on from entries submitted.

1) Get-ChildItem -Recurse

When you need to retrieve files from paths with subfolders the Recurse parameter of Get-ChildItem makes this really easy. For instance

Get-ChildItem -Path C:\Application\Log -Filter *.log -Recurse

is a really easy way to return everything below C:\Application\Log. In the specific instance of this event, this is OK because you only have three subfolders, but potentially there could be a lot more and some of them might not be relevant.

Event1a

 

So a better way to do this might be to use wildcards in your path. For instance here we know that all of the subfolders that we are interested in contain the string ‘app’ so we could use something like the below:

Get-ChildItem -Path C:\Application\Log\*app*\*.log

Note you can use the * wildcard not only for part of the filename, but also the directory and you can combine multiple wildcards.

Event1b

2) Copy-Item followed by Remove-Item

The goal of the event is to archive files from the expensive storage to cheaper, archived storage. Some examples used a two-step process to do this with:

Copy-Item.....

Remove-Item.....

(and some did not even include the Remove-Item, so the files are duplicated) No need to do that, you can use Move-Item to make it a one step process.

3) Maintaining the Folder Structure at the Destination

Make sure you read all of the requirements for the event. One of which was to maintain the folder structure at the destination archive. So something like the following will simply end up with all of the log files in one unmanageable folder.

Get-ChildItem -Path C:\Application\Log\*app*\*.log -file | Move-Item -Destination C:\Archive

Event1c

Since we are not using the Recurse parameter in the initial query, an attempt to move the file will fail because the path does not exist. Instead we can do something similar to the touch command in Unix to first create an empty file, then overwrite it with the file move.


Get-ChildItem -Path C:\Application\Log\*app*\*.log | ForEach-Object {New-Item -ItemType File -Path "C:\Archive\$($_.Directory.Name)\$($_.Name)" -Force; Move-Item $_ -Destination "C:\Archive\$($_.Directory.Name)" -Force}

Event1d

Looking forward to seeing entries for the next event. Remember you can still join in and there are plenty of prizes to be won!

ScriptingGames

PowerShell Scripting Games 2013

Looking for a good way to start learning PowerShell or fancy testing yourself with some more advanced problems to solve? It’s time again for the annual Scripting Games and this year the PowerShell community are running the event, ably supported by the Microsoft Scripting Guy.

There are separate Beginner and Advanced tracks and plenty of prizes to be won in each event. I’ll be helping out with the other community judges to highlight some of the entries. The Scripting Games are a great way to get started learning PowerShell, in fact it was one of the main resources I used when I first started.

Full details on how to enter and other information here.

PowerShell-Scripting-Games-Logo