A Peculiar Parse
One of the best enhancements to Powershell was the inclusion of custom classes in v5. We originally wrote scripts, then we wrote cmdlets, followed by modules, and now we’ve graduated, with Class.
I recently decided I wanted to write some code that would build a website. What better way to do that than by creating a class just for me? That’s rhetorical by the way. My early class code looked like this:
class mysite { [string]$SiteName = 'mysite' [string]$PhysPath = 'c:\mysite' [string]$Binding = '*:8000:' mysite(){ Import-Module IISAdministration,WebAdministration } [void]CreateSite(){ $newsite = @{ Name = $this.SiteName PhysicalPath = $this.PhysPath BindingInformation = $this.Binding } New-IISSite @newsite (Get-IISServerManager).CommitChanges() } } With this code I’m able to create my IIS website and see it in IIS Manager. But then I thought it’d be great to add the object representing the new site to my custom class. To do this I’ll need to create another property. It’s generally a good idea to cast properties as the appropriate object type. That means adding a new property to the class and loading the appropriate namespaces so the casting would work. I also updated my method to pass the object representing my website to the new property.
class mysite { [string]$SiteName = 'mysite' [string]$PhysPath = 'c:\mysite' [string]$Binding = '*:8000:' [Microsoft.Web.Administration.Site[]]$SiteObject mysite(){ [void][System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.Web.Administration') [void][System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.Web.Management') Import-Module IISAdministration,WebAdministration } [void]CreateSite(){ $newsite = @{ Name = $this.SiteName PhysicalPath = $this.PhysPath BindingInformation = $this.Binding } $this.SiteObject += New-IISSite @newsite -Passthru (Get-IISServerManager).CommitChanges() } } Looks great right? I was able to create my new site and see it in IIS Manager. The next day I wanted to try it out again so I deleted my website, loaded my code, and then got hit with a nasty error from the parser.

`PS C:\Dev> . .\powershellorg.ps1 At C:\Dev\powershellorg.ps1:5 char:4
- [Microsoft.Web.Administration.Site[]]$SiteObject
Unable to find type [Microsoft.Web.Administration.Site]. + CategoryInfo : ParserError: (:) [], ParseException + FullyQualifiedErrorId : TypeNotFound `Turns out, the parser in powershell is reading my code and sees an object type it doesn’t know. That would be my new property with the casting to [Microsoft.Web.Administration.Site]. At this point, the namespace containing the class I’m casting as hasn’t been loaded because that code is in the class constructor. So I figure, no problem! I’ll just load the namespaces before I define my class, score one point for Colyn!
[void][System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.Web.Administration') [void][System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.Web.Management') class mysite { [string]$SiteName = 'mysite' [string]$PhysPath = 'c:\mysite' [string]$Binding = '*:8000:' [Microsoft.Web.Administration.Site[]]$SiteObject mysite(){ Import-Module IISAdministration,WebAdministration } [void]CreateSite(){ $newsite = @{ Name = $this.SiteName PhysicalPath = $this.PhysPath BindingInformation = $this.Binding } $this.SiteObject += New-IISSite @newsite -Passthru (Get-IISServerManager).CommitChanges() } } Or so I thought, as it turns out I still receive the same exception. Going back to my troubleshooting skills I stepped through my code in the ISE, without exception. Wait, what? That’s right, there was no exception when I stepped through my code. Thinking I might have fat fingered my code, or maybe didn’t save correctly, I tried again. Same error.
Upon further research I discovered that the parsing protocol in powershell doesn’t read linearly. In its early passes over my code it observed I was creating a class and decided to load the class first. Because the [mysite] class is loading before my reflection calls, the code bombs. +1 for non linear dynamics. This is true even when implementing the ‘using namespace’ capability that launched with v5:
using namespace Microsoft.Web.Administration; using namespace Microsoft.Web.Management; class mysite { [string]$SiteName = 'mysite' [string]$PhysPath = 'c:\mysite' [string]$Binding = '*:8000:' [Microsoft.Web.Administration.Site[]]$SiteObject mysite(){ Import-Module IISAdministration,WebAdministration } [void]CreateSite(){ $newsite = @{ Name = $this.SiteName PhysicalPath = $this.PhysPath BindingInformation = $this.Binding } $this.SiteObject += New-IISSite @newsite -Passthru (Get-IISServerManager).CommitChanges() } } I determined two ways around this problem. The first was to keep the class in a separate file, but create a new .ps1 file that would load the dependent namespaces and then use dot sourcing to load the class file. I did a quick experiment to test this assumption which gave positive reinforcement for the idea:

Of course the polymorphism of powershell allows a less cumbersome and equally less exact solution. I can simply recast the property as a generic object.
class mysite { [string]$SiteName = 'mysite' [string]$PhysPath = 'c:\mysite' [string]$Binding = '*:8000:' [Object[]]$SiteObject mysite(){ [void][System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.Web.Administration') [void][System.Reflection.Assembly]::LoadWithPartialName( 'Microsoft.Web.Management') Import-Module IISAdministration,WebAdministration } [void]CreateSite(){ $newsite = @{ Name = $this.SiteName PhysicalPath = $this.PhysPath BindingInformation = $this.Binding } $this.SiteObject += New-IISSite @newsite -Passthru (Get-IISServerManager).CommitChanges() } } As with anything in Powershell or coding in general, there’s always more than one way to achieve a goal. The lesson learned in this experience is that custom classes will always be loaded ahead of the rest of your code. You can work around this by abstracting your classes to a separate file or “library” to ensure your code executes in the order you intend. If you get a TypeNotFound error from a casting call in your class, you can use the code abstraction method or simply recast to a default but similar type.
Related Articles
Iron Scripter: Learn PowerShell through code challenges
Hello, friends! Today I want to talk about the Iron Scripter code challenges and the accompanying website. The challenges are excellent for practicing challenging concepts. What’s that you say? Not familiar with Iron Scripter? Let’s get you up to speed. Iron Scripter: A brief history lesson The Iron Scripter website is part of the PowerShell.org family and provides material for the Iron Scripter challenge that takes place at PowerShell Summit each year.
Complete Guide to PowerShell Punctuation
Quick as you can, can you explain what each of these different parentheses-, brace-, and bracket-laden expressions does? ${save-items} ${C:tmp.txt} $($x=1;$y=2;$x;$y) (1,2,3 -join '*') (8 + 4)/2 $hashTable.ContainsKey($x) @(1) @{abc='hello'} {param($color="red"); "color=$color"} $hash['blue'] [Regex]::Escape($x) [int]"5.2" When you’re reading someone else’s PowerShell code, you will come across many of these constructs, and more. And you know how challenging it can be to search for punctuation on the web (symbolhound.com not withstanding) !
Convert VBA Macros To PowerShell for Microsoft Office Automation
There is a lot of documentation out there for interacting with Microsoft Office including Outlook, Excel, Word, etc with Visual Basic for Applications (VBA). A lot of time you may only be able to find VBA examples. VBA’s require template files to be sent to the desktop and are a real hassle when trying to automate across multiple machines. There are not many A to B examples of translating VBA to PowerShell so I took a problem I had solved in the past and presented the before and after.