Monthly Archives: May 2015

Return File Sizes in Bytes, KBs, MBs, and GBs, at the Same Time

I scanned a recent forum post on PowerShell.org where the user seemed (again, I scanned it) to want to run some files through Get-ChildItem and Select-Object, and report the size in something other than the bytes default. It didn’t appear he, or she, wanted all the files in one of the measurement groups: B, KB, MB, or GB, but instead in their proper measurement group, dependent on the file’s size.

That may be hard to understand at first read, so let me try and explain it another way. If a file has less than 1,024 bytes, then it should be reported in bytes, if it has 1,024 – 1,048,575 bytes, then it should be reported in Kilobytes, if it has 1,048,576 – 1,073,741,824 bytes then it should be reported Megabytes, and if it has 1,073,741,825 or more bytes, then it should be reported in Gigabytes.

I wrote a long, “one-liner” to do this and have included it, and some sample output, below. I don’t profess to guarantee this doesn’t have any errors, so if you find some, then let me know. In addition, it shows a nice example of a switch statement inside the Expression portion of a calculated property. Fancy.

Get-ChildItem -Path 'C:\test' |
    Select-Object Name,
        @{L='Size';E={
                switch ($_.Length) {
                    # Bytes
                    {$_ -eq 0} {"$('{0:N2}' -f $_) bytes"; break}
                    {$_ -eq 1} {"$('{0:N2}' -f $_) byte"; break}
                    {($_ -gt 1) -and ($_ -le 1023)} {"$('{0:N2}' -f $_) bytes"; break}

                    # Kilobytes
                    {$_ -eq 1024} {"$('{0:N2}' -f ($_/1KB)) Kilobyte"; break}
                    {($_ -gt 1024) -and ($_ -le 1048575)} {"$('{0:N2}' -f ($_/1KB)) Kilobytes"; break}

                    # Megabytes
                    {$_ -eq 1048576} {"$('{0:N2}' -f ($_/1MB)) Megabyte"; break}
                    {($_ -gt 1048576) -and ($_ -le 1073741824)} {"$('{0:N2}' -f ($_/1MB)) Megabytes"; break}

                    # Gigabytes
                    {$_ -eq 1073741825} {"$('{0:N2}' -f ($_/1GB)) Gigabyte"; break}
                    {$_ -gt 1073741825} {"$('{0:N2}' -f ($_/1GB)) Gigabytes"; break}

                    default {Write-Warning -Message 'Unknown Error.'}
                }
            }
        } | Format-Table -AutoSize

Name           Size
----           ----
My-A-File.txt  1.00 byte
My-A-File2.txt 445.00 bytes
My-B-File.txt  1.00 Kilobyte
My-B-File2.txt 1.30 Kilobytes
My-C-File.txt  2.09 Megabytes
My-D-File.txt  3.59 Gigabytes

I can easily see how someone might want to remove the singular vs. plural: Kilobyte vs. Kilobytes, and just use B, KB, MB, and GB, and so…

Update: I gave this some more thought today, and I really didn’t feel like it was okay to not include a modified version that uses abbreviations (B, KB, MB, GB) instead of the full words, as in the previous example. It has removed some complexity, as well, as you can see below.

Get-ChildItem -Path 'C:\test' |
    Select-Object Name,
        @{L='Size';E={
                switch ($_.Length) {
                    # Bytes
                    {($_ -ge 0) -and ($_ -le 1023)} {"$('{0:N2}' -f $_) B"; break}

                    # Kilobytes
                    {($_ -ge 1024) -and ($_ -le 1048575)} {"$('{0:N2}' -f ($_/1KB)) KB"; break}

                    # Megabytes
                    {($_ -ge 1048576) -and ($_ -le 1073741824)} {"$('{0:N2}' -f ($_/1MB)) MB"; break}

                    # Gigabytes
                    {$_ -ge 1073741825} {"$('{0:N2}' -f ($_/1GB)) GB"; break}

                    default {Write-Warning -Message 'Unknown Error.'}
                }
            }
        } | Format-Table -AutoSize

Name           Size
----           ----
My-A-File.txt  1.00 B
My-A-File2.txt 445.00 B
My-B-File.txt  1.00 KB
My-B-File2.txt 1.30 KB
My-C-File.txt  2.09 MB
My-D-File.txt  3.59 GB

Fix Register-PSSessionConfiguration Error 1326

I guess if you do this long enough, you start finding and reporting on errors before anyone else does. My decision to write today began because of this error message: “Register-PSSessionConfiguration : The verification of the runAs user credentials failed with the error 1326.”

After receiving the error, I took it to Google, and wrapped it in double quotes, only to find there were no relevant results. Once I had a solution, I decided I should do my part to help the next person that encounters this error. As you may be able to conclude, the error message appeared when I tried to register a PowerShell constrained endpoint, using the Register-PSSessionConfiguration cmdlet’s -RunAsCredential parameter.

The primary reason I figured this out so quickly, was because I noticed that the user logon name I chose ended up being longer than my ‘Pre-Windows 2000 logon.’ Think SamAccountName (and its length limitation) vs. the Name property.

It’s apparent (now) that the Register-PSSessionConfiguration’s -RunAsCredential Parameter is expecting the username portion of the PSCredential object to be the SamAccountName, even if the help file doesn’t explicitly indicate that. Hope this helps someone else.

Update: I decided to do the same Google Search I did last week (for the error message), and now something is showing up: this post. Yea, Internet!

Fix-Register-PSSessionConfiguration-Error-1326-01

Give a Parameter a Default Value (Part II)

Part I: http://tommymaynard.com/quick-learn-give-a-parameter-a-default-value-2015
Part III: http://tommymaynard.com/quick-learn-give-a-parameter-a-default-value-part-iii-2016

An old co-worker and friend contacted me last week. We hadn’t chatted since the last time I was interviewing for a job — a job I have now (well, pretty close anyway). I remember telling him I wanted a job that allowed me to work with Windows PowerShell. While he probably wasn’t surprised to hear this job did just that, he might have been, to hear I had started this site — a site using my name, and all about PowerShell. It’s a pretty serious commitment to associate your name with a technology, and continue to provide new content.

He mentioned to me that he wasn’t aware of the $PSDefaultParameterValues preference variable until he read this post. No joke, but it’s exciting to know that something I wrote was helpful for him. You see, this isn’t your average intelligence IT Pro, no, this is walking, talking IT genius. You know the kind — one of the ones you’d hire first, if you opened your own consulting business. In fact, during that same first chat, I discovered that he spoke at the Microsoft Higher-Education Conference in October 2014. He’s definitely doing something right.

As last weekend passed, I occasionally thought about that $PSDefaultParameterValues post and decided I should add something more to it, especially since I highlighted what I would consider to be the less used approach for populating this variable. First off, for those that haven’t read the previous post, the $PSDefaultParameterValues variable allows you to specify a default value for a cmdlet’s, or function’s, parameter(s).

For example, if I wanted the Get-Help cmdlet to always include the -ShowWindow parameter, then I can add that default value to the cmdlet like so:

PS C:\> $PSDefaultParameterValues
PS C:\> # Proof the variable is empty.
PS C:\> $PSDefaultParameterValues.Add('Get-Help:ShowWindow',$true)
PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Get-Help:ShowWindow            True

With this value set, every time we use the Get-Help cmdlet, it will include the -ShowWindow parameter, even though I don’t specifically enter it at the time the command is run. In the previous example, we use the .Add() method to add a key-value pair; however, I suspect that most people will actually be more likely to use a hash table to add the cmdlet and parameter, and its new, default parameter value. Here’s the same example as above using the hash table option.

PS C:\> $PSDefaultParameterValue
PS C:\> # Proof the variable is empty.
PS C:\> $PSDefaultParameterValues = @{'Get-Help:ShowWindow' = $true}
PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Get-Help:ShowWindow            True

Now for the reason I led with with .Add() method: If you use the hash table option above, and the variable is already populated, then it’s going to overwrite the value it’s already storing, unless we use the += assignment operator. Follow along in the next few examples under the assumption that $PSDefaultParameterValues, is already populated from the previous example.

PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Get-Help:ShowWindow            True

PS C:\> $PSDefaultParameterValues = @{'Get-ADUser:Server' = 'MyClosestDC'}
PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Get-ADUser:Server              MyClosestDC

In the example above, using the = assignment operator overwrote our Get-Help ShowWindow key-value pair, as it would with any populated variable. The idea here is that we either need to assign all the parameter default values at once (when using a hash table), or use the += assignment operator to append other key-value pairs. Here’s both ways:

PS C:\> $PSDefaultParameterValues
PS C:\> # Proof the variable is empty.
PS C:\> $PSDefaultParameterValues = @{'Get-Help:ShowWindow' = $true;'Get-ADUser:Server' = 'MyClosestDC'}
PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Get-ADUser:Server              MyClosestDC
Get-Help:ShowWindow            True

PS C:\> $PSDefaultParameterValues = $null
PS C:\> $PSDefaultParameterValues
PS C:\> # Proof the variable is empty.
PS C:\> $PSDefaultParameterValues = @{'Get-Help:ShowWindow' = $true}
PS C:\> $PSDefaultParameterValues += @{'Get-ADUser:Server' = 'MyClosestDC'}
PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Get-ADUser:Server              MyClosestDC
Get-Help:ShowWindow            True

That’s all there is to it. If you’re going to use a hash table and assign values to your $PSDefaultParameterValues at different times, then be sure to use the correct assignment operator, or use the .Add() method — it’s up to you. For me, I populate this variable in my profile, so overwriting it, is something in which I’m not concerned. Thanks for reading!