Today, I was updating a script I wrote a while ago, and I wanted to streamline the processing loops once input was received. This particular script took parameters for:
- Identity (as an email address or UserPrincipalName)
- CSV (with either no header or a header of UserPrincipalName)
- Target environment type (either Active Directory or Office 365/Azure AD, which return a UserPrincipalName property with Get-ADUser or Get-AzureADUser)
I had gone the “easy” route and just done a simple If/Then to see if the Identity parameter had been passed, and if it had, run a separate chunk of code (which made troubleshooting or updates much harder since I had to keep two branches of the code synced when I made updates).
So, today, as I had to touch big chunks of code, I decided there has to be a better way. And, I’m happy to report, as with most scripting things, there is.
How I solved today’s problem was by creating what appeared to be an array list or collection with a header and one value (in actuality, it’s an array with a PSCustomObject that has two NoteProperty members added). That way, I could re-use the same code block for the single Identity as I was for the imported CSV or results of Get-ADUser or Get-AzureADUser, because you can use dot notation to access the NoteProperty values. In this case, I wanted what appeared to be an array of one value with the UserPrincipalName header.
And, it ended up being pretty simple. Here’s the reduced snippet:
param([string]$Identity) $Params = $PSBoundParameters.Keys switch ($Params) { Identity { If ($Identity -eq $null) { Write-Log -ConsoleOutput -LogLevel ERROR -Message "If you're going to specify an identity, specify an identity." Get-Help $($MyInvocation.Line).ToString() -Examples Exit } Else { [array]$users = $Identity | ForEach-Object { [PSCustomObject]@{ 'UserPrincipalName' = $Identity } } } } }
That’s the magic! Again, in slow-mo:
[array]$variable = $stringdata | Foreach-Object { [PSCustomObject]@{'arrayHeaderValue' = $stringdata }}
You can even add multiple values to your PSCustomObject. You’ll just need to type your $variable as a [System.Collections.ArrayList] to make it so. In this case, I want to create one column header called “mail” using the values in my source array; I want to make another column called “Date” using today’s date (because I’m lazy). The sky’s kinda the limit here.
[System.Collections.ArrayList]$ArrayWithHeader = @() $ArrayOfValues = @('a@b.com','b@c.com','c@d.com','d@e.com') foreach ($obj in $ArrayOfValues) { $val = [pscustomobject]@{'mail'=$obj;'date'=(Get-Date)} $ArrayWithHeader.add($val) | Out-Null $val=$null }
It works just the way you would want it to.
If you want to learn tons about arrays and crazy stuff you can do with them, I’d start with Kevin Marquette’s “Everything you wanted to know about arrays” (he’s apparently as creative at naming stuff as I am).