PowerShell.cz
Get-World | ConvertTo-PowerShell
Get-World | ConvertTo-PowerShell
May 6th
As I mentioned in the previous article working with errors was the biggest pain of most of the entries for the first advanced event.
Firstly the description does not say the errors need to be handled in any way, it only mentions you need to clearly display them, PowerShell does that by default. So if you would not use any error handling you would probably still comply with the requirements.
On the other hand when a standard PowerShell cmdlet fails it stops on the first error for each item, reports the error and jumps to the next item. This is what most of you tried to achieve, but not always successfully. Error records got stripped to just error messages informing user, terminating errors became non-terminating and vice versa.
The core of the task is to move files from one location to another. The Move-Item cmdlet is the most reasonable choice, but it has one limitation that must be taken into account: If the destination path (folder) does not exist the operation ends with a non-terminating exception.
For the sake of simplicity let’s assume the source and destination root paths exist because I tested their availability while validating the parameters. There I also made sure the path is a FileSystem path not a registry or other path (believe or not this is more important than the first check). I also assume the remaining parameters are valid.
The goal is to move as much files as I can to the new location. Freeing as much disk space as I can for Dr. Scripto.
My script is going to be laid out like this:
$sourceItem = #[1] Get items recursively and filter them according to the requirements.
foreach ($currentItem in $sourceItem)
{
#[2] Form the path to the resulting directory.
#[3] If the destination directory doesn't exist, create it.
#[4] Move the current item.
}
If any of the last three steps (2, 3 or 4) fails the function should progress to the next item in the list. I am going to force this behavior using ErrorAction on the cmdlets and Try Catch block that will capture only two types of exceptions:
[Management.Automation.MethodInvocationException]
these may raise from .NET calls.
[Management.Automation.ActionPreferenceStopException]
these are raised when cmdlet fails and has the ErrorAction set to Stop.
All these exceptions were originally non-terminating, so after doing the clean-up I write them back to the screen using the Write-Error, keeping all the original information.
The important thing is most of the possible exceptions (like OutOfMemoryException) are still able to pass by unaffected. So if the script fails the terminating exceptions bubble up and possibly terminate the script, the non-terminating exceptions are written to the error stream and the scripts progresses.
Here is the example code:
$Source = 'C:\Windows\logs'
$Destination = 'G:'
$Before = (Get-Date).addDays(-90)
$Filter = '*.log'
$sourceItem = Get-ChildItem -Recurse -Path $Source -File -Filter $Filter |
Where-Object {
$_.LastWriteTime -lt $Before
}
foreach ($currentItem in $sourceItem)
{
$destinationCreated = $false
try
{
$destinationDirectory = $currentItem.Directory.FullName.Replace($Source,$Destination)
if (-not ( Test-Path -Path $destinationDirectory -ErrorAction Stop))
{
$destinationCreated = [bool]( New-Item -Path $destinationDirectory -ItemType Directory -ErrorAction Stop )
}
Move-Item -Path $currentItem.FullName -Destination $destinationDirectory -ErrorAction Stop
}
catch [Management.Automation.MethodInvocationException], [Management.Automation.ActionPreferenceStopException]
{
if ( $destinationCreated )
{
Remove-Item -Path $destinationDirectory -Force
}
Write-Error -ErrorRecord $_
}
}
May 4th
Here are few tips on scripting I’d like to share. Some of them are inspired by the entries for first Scripting Games event. Some of them are just related.
Before I start the rant please keep in mind I understand criticizing is a lot easier than writing the script and making it awesome. Good luck with the next event!
Variables
Use variables and name them properly. Variables are an easy way to label the data you work with. There are few things to focus on:
Apr 16th
Talking about geeky ways to do stuff with Jaap Brasser I’ve stumbled upon this gif, where someone creates what I suppose is C code using MsPaint. Pretty awesome stuff, even if the code won’t compile afterwards because of the bmp header. Wondering how some PowerShell code would look like as a bmp we attempted to write a function to automate the process, and here is my take on it:
function ConvertTo-Bitmap ([String]$Source,
[String]$Destination=([IO.Path]::ChangeExtension($Source,'bmp')))
{
$header = 66,77,58,0,0,0,0,0,0,0,54,0,0,0,40,0,0,0,1,0,0,0,
1,0,0,0,1,0,24,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
$File = Get-Content $Source -Encoding Byte | Select-Object -Skip 3
$Reminder = $File.Count % 4
$File += ,0 * $Reminder
$size = [Math]::Sqrt($file.Count/4)
$header[22] = $size #height
$header[18] = $size #width
Set-Content -path $Destination -Force -Encoding Byte -Value ([byte[]]($header+$File))
}
Convertto-Bitmap -Source ".\hello.ps1"
Here is an example of “Hello World!” script converted to bmp:

The image is of course zoomed out, here is link to the original.
The logic behind the code is pretty simple. 54 byte long file header and appropriate file extension is what makes a file a bmp file. The header is represented as an array of byte values in the code. The header contains information about the file contents, most importantly its width (offset 18) and height (offset 22). If these values are set too low not all data in the file are visible. If they are too high the file comes out corrupted so I need to calculate the exact value. The header is followed by image data (4byte groups) created from byte values of the letters. All of this is output to a file as byte data and named appropriately.
There are few things I did not take into account, I blindly assume the input values are correct and the input file is utf-8 encoded.
It turned out my logic behing the first version was failed and it in fact truncates some of the data so here is updated version that tries to fit the data to as much square area as it can.
function ConvertTo-Bitmap ([String]$Source,
[String]$Destination=([IO.Path]::ChangeExtension($Source,'bmp')))
{
$header = 66,77,58,0,0,0,0,0,0,0,54,0,0,0,40,0,0,0,1,0,0,0,
1,0,0,0,1,0,24,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
$File = Get-Content $Source -Encoding Byte | Select-Object -Skip 3
#file needs to be created of 4 byte groups - pixels
$groupSize = 4
#append filler if needed
$filler = 0
$fillerCount = 4 - ($File.Count % $groupSize)
$file += ,$filler * $fillerCount
#calculate the dimensions of the picture
$pixelCount = $file.Count / $groupSize
$dimensions = Get-Dimensions -Number $pixelCount
$header[18] = $dimensions.Width
$header[22] = $dimensions.Height
Set-Content -path $Destination -Force -Encoding Byte -Value ([byte[]]($header+$File))
}
function Get-Dimensions ([int]$Number) {
$dividers = for ($divider= $number ; $divider -gt 0; $divider)
{
$result = $number / $divider
if ($result -eq [int]$result) { $result }
$divider--
}
#make sure I am working with array - important for 1
$dividers = @($dividers)
$dividersCount =$dividers.count
$half = [Math]::Truncate($dividersCount/2)
if ($dividersCount % 2)
{
$height = $dividers[$half]
$width = $dividers[$half]
}
else
{
$height = $dividers[$half]
$width = $dividers[$half-1]
}
new-object -TypeName psObject -Property @{Height = $height; Width = $width}
}
Convertto-Bitmap -Source ".\Hello.ps1"
Apr 4th
Just a quick post on something I saw lot of people wonder about: How do you hide and show console window when using forms with PowerShell?
The p/Invoke calls required can be found in numerous web resources and also in Poweshell in Action book.
Here is prototype of the soulution:
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
function Show-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
#5 show
[Console.Window]::ShowWindow($consolePtr, 5)
}
function Hide-Console {
$consolePtr = [Console.Window]::GetConsoleWindow()
#0 hide
[Console.Window]::ShowWindow($consolePtr, 0)
}
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Form = New-Object System.Windows.Forms.Form
$showButton = New-Object System.Windows.Forms.Button
$showButton.Text = 'ShowConsole'
$showButton.Top = 10
$showButton.Left = 10
$showButton.Width = 100
$showButton.add_Click({Show-Console})
$form.controls.Add($showButton)
$hideButton = New-Object System.Windows.Forms.Button
$hideButton.Text = 'HideConsole'
$hideButton.Top = 60
$hideButton.Left = 10
$hideButton.Width = 100
$hideButton.add_Click({hide-Console})
$form.controls.Add($hideButton)
$Form.ShowDialog()
Description of the functions and more possible values for the ShowWindow can be, as usual, found in Microsoft documentation:
GetConsoleWindow function
ShowWindow function
Mar 22nd
Nowadays I am trying to implement something that includes lot of P/Invoke calls, and several DWORD flags are included in the calls. The DWORD is unsigned 32-bit integer and is usually represented like hexadecimal number – 0x000000ff. At first it all seemed peachy until it turned out that the standard PowerShell converts the hexadecimal representation of number to integer (values less than 0 are possible) and not the unsigned integer (negative numbers are not possible). Let’s see an example:
Here is the maximum value of the DWORD represented in hexadecimal format 0xffffffff. I expect it to be 4294967295 (the same as the maximum value of unsigned 32-bit integer [uint32]::MaxValue) but running it in PowerShell console returns -1, a value clearly not belonging to scope of the UInt32 type.
I realized I need to do the conversion myself and found it can be done easily using static methods of the System.Convert class. In the example I specify a hexadecimal representation of the number as a string and the base of the hexadecimal number which is 16.
[Convert]::ToUInt32("0xffffffff",16)
Note: Changing the base value to 2 enables you to work with binary numbers, changing it to 8 enables you to work with octal number, changing it to 10 makes it work with decimal numbers (default).
This is easy, but inconvenient and error-prone so I created function called ConvertFrom-Dword that validates the input values for me and returns the number as unsigned integer:
function ConvertFrom-Dword
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)]
[ValidatePattern("^(0x)?(0+)?[0-9|a-f]{1,8}`$")]
[string]$Value
)
#0xffffffff -band 0xFFFFFFFFL is also possible
$base = 16
Write-Verbose "Converting DWORD value $value to decimal."
[Convert]::ToUInt32($Value,$base)
}
ConvertFrom-Dword -Value 0xffffffff
(ConvertFrom-Dword -Value 0xffffffff).getType().fullname
4294967295
System.UInt32
This is easier but still not perfect, but for the time being it will do.
In real life we can for example take the CreateFile function documented here. By the name of the function you would probably say it is used just to create files, but it is also able to open existing file. When you perform this action you can decide if you need the file opened exclusively (lock it) or if you want to share access to the file with other processes. For that purpose there is parameter dwShareMode you can set by specifying correct “flags” (DWORD values).
The description on the linked page says:
The requested sharing mode of the file or device, which can be read, write, both, delete, all of these, or none (refer to the following table).
0
0×00000000
FILE_SHARE_DELETE
0×00000004
FILE_SHARE_READ
0×00000001
FILE_SHARE_WRITE
0×00000002
If you read carefully you probably wonder how you specify the “both” and “all of them” cases if there are no such items in the table. The solution is connecting them by the “-bor” (bit OR) operator. If you want to share both write and read you do: 0×00000001 –bor 0×00000002. Which returns 3 or 0×00000003 in case you use this little trick.
function ConvertTo-Dword ([uint32]$Number)
{
"0x{0:x8}" -f ($Number)
}
ConvertTo-Dword 3
0x00000003
The operation –bor did, may look like a simple adding but it is not because 1 –bor 1 = 1, instead it does operation on binary representation of the number. Look at the items in the table again. Why is 0×00000003 missing?

Now I see I need some more instruments to work easily with this type of data, back to console…
Mar 1st
Recently I have come across Microsoft Team Foundation Server Service preview. The service is currently offered for free and supports both TFS and Git version control systems. So I have signed up
The only thing that reminded to make use of it was to connect PowerGUI to the service which turned out to be quite trivial. So I will show you how to do step by step:
Some basic documentation on connecting PowerGUI to TFS is provided on the PowerGUI Wiki. To be able to connect to the TFS Service you need newer MSSCCI Provider installed. Both 32-bit and 64-bit version are available on Microsoft pages, but my PowerGUI x64 seems to detect only the 32-bit version.
When you have downloaded and installed the client you need to restart your PowerGUI editor and go to Tools > Options… > Version Control and select Team foundation Server MSSCCI provider as your current provider.
Then, in the main editor window, go to new Version Control menu and choose Get files from Version Control. New windows appears, where you can choose which provider you want to use. You probably have none there yet so you need to add one by clicking Servers… > Add… This will get you to this menu:

Here you have to specify URL to your TFSS account followed by “/DefaultCollection”. Click OK and you should be prompted to login to your Microsoft account:

Logging in takes few moments and then you are hopefully presented with this window:
Just click Cancel to return to the selector:

Click OK here and you are good to go.
In the next step you need to choose local folder to store the data and also choose server path to the project you work on.

Next you need to choose file you will edit, I have chosen to name it hello.ps1.

If you are yet to create one go to your browser, navigate to your TFSS web page and create new Team project.
Now you have your file opened and you can CheckOut, make your changes and CheckIn.
Feb 25th
One of the things that I always wondered about, is how you find out if strict mode is set in PowerShell session. I have put the problem aside until answer was posted to the Powershell.com forum. Finding out where and how the value is stored was the easy part. I just opened the .NET Reflector and looked at the definition of the SetStrictModeCommand. Getting the value from PowerShell session was much harder. Few days of casual digging and it turns out the answer can be retrieved using Reflection. As I am new to the whole Reflection thing it was pretty hard to get the basic principles but fortunately this POSHCode article came to rescue. It contains basically all I needed to extract the info.
function Get-Field
{
[CmdletBinding()]
param (
[Parameter(Position=0,Mandatory=$true)]
$InputObject
)
$type = $InputObject.gettype()
$publicNonPublic = [Reflection.BindingFlags]::Public -bor [Reflection.BindingFlags]::NonPublic
$instance = $publicNonPublic -bor [Reflection.BindingFlags]::Instance
$getField = $instance -bor [Reflection.BindingFlags]::GetField
$fields = $type.GetFields($instance)
$result = @{}
$fields | Foreach-Object { $result[$_.Name] = $type.InvokeMember($_.Name, $getField, $null, $InputObject, $null) }
$result
}
function Get-StrictMode
{
###if strict mode is set return its version, otherwise return nothing
$context = (Get-Field $ExecutionContext)._context
$sessionState = (Get-Field $context)._engineSessionState
$scopes = Get-Field $sessionState
$globalScope = Get-Field ($scopes._globalScope)
#different hosts refer to the field differently trying to fix it
try
{
$version = $globalScope."k__BackingField"
}
catch [System.Management.Automation.RuntimeException]
{
$errorId = $_.Exception.ErrorRecord.FullyQualifiedErrorId
if (-not ($errorId -eq "PropertyNotFoundStrict"))
{
throw $_
}
}
try
{
$version = $globalScope.StrictModeVersion
}
catch [System.Management.Automation.RuntimeException]
{
$errorId = $_.Exception.ErrorRecord.FullyQualifiedErrorId
if (-not ($errorId -eq "PropertyNotFoundStrict"))
{
throw $_
}
}
##Major version is grater than 0 if the strict mode is set
#test if the variable is set first to avoid strict mode error
if ($version)
{
if ($Version.Major -gt 0)
{
$version
}
}
}
Set-StrictMode -Version latest
Get-strictMode
Set-StrictMode -Version 2
Get-strictMode
Set-StrictMode -Version 1
Get-strictMode
Set-StrictMode -Off
Get-strictMode
The code is not perfect because only the state from global scope is retrieved. Ideally it should be retrieved from the current scope, but unfortunately I am unable to do so (Suggestions please.). In the current state the strict mode appears as not set unless you set it in to the global scope. This returns incorrect results:
&{
Set-StrictMode -Version 2
Get-StrictMode
}
Jan 19th
Playing around with exceptions I got really tired of walking up the type tree using .getType().BaseType.GetType().fullname so I decided to create a simple Resolve-Type function. The functions output is not very well formatted, I may improve on this later.
function Resolve-Type
{
param(
[Parameter(ParameterSetName="Type",Position=0)]
[String]
$TypeName,
[Parameter(ParameterSetName="Object",Position=0,ValueFromPipeline=$true)]
[Object]
$InputObject
)
process {
switch ($PsCmdlet.ParameterSetName)
{
"Type" {
if ($TypeName -as [Type])
{
$TypeInfo = [Type]$TypeName
}
else
{
Write-Error 'The specified type is not correct. Make sure the assembly is loaded.'
}
}
"Object" { $TypeInfo = $inputObject.GetType() }
}
Function ResolveCore ([System.Reflection.TypeInfo]$TypeInfo)
{
$TypeInfo.fullname
if ( $TypeInfo.BaseType)
{
$base = $TypeInfo.BaseType.asType()
ResolveCore $base
}
}
#call the recursive function
ResolveCore -TypeInfo $TypeInfo
}
}
Resolve-Type -TypeName IO.File
Example 1: System.IO.File System.Object Example 2: System.Management.Automation.Internal.Host.InternalHost System.Management.Automation.Host.PSHost System.Object Example 3: System.Management.Automation.ItemNotFoundException System.Management.Automation.SessionStateException System.Management.Automation.RuntimeException System.SystemException System.Exception System.Object Example 4: System.String System.Object
Jan 14th
Lurking through the PowerShell inner workings facing problem that you have no clue what caused is not a rare occasion. Tracing the command/expression usually gives you at least a peek on the problem’s domain but there is one slight problem with the Trace-Command cmdlet. The Name parameter produces wast amount of output when used with asterisk wildcard. In this article I used it with success because I was pretty sure what I was looking for. Going through pages of debug output is not my favorite thing to do, so I looked what trace sources produce the most of the amount with the less usefull information and narrowed it down to the ConsoleHost provider and sometimes the Type* providers. Now only if there was a way to get all the sources excluding the listed ones. Looking at the definition of the Name parametes on the Trace-Command cmdlet I see it accepts array of strings as input. From now it is easy:
#filter out unneeded sources
[string]$pattern = 'consolehost|type'
$debugSources = Get-TraceSource | ?{$_.name -notmatch $pattern} | select -ExpandProperty name
#trace the expression
[scriptblock]$expression = {Get-Process | Select-Object -First 1}
Trace-Command -name $DebugSources -pshost -Expression $expression
Fling it into a function to be able to reuse it and finish with this:
function Trace-CommandRestricted ([scriptblock]$expression,[string[]]$Exclude)
{
$patternResult = $Exclude -join '|'
#filter out unneeded sources
$debugSources = Get-TraceSource | ?{$_.name -notmatch $patternResult} | select -ExpandProperty name
Trace-Command -name $DebugSources -pshost -Expression $expression
}
$expression = {Get-Process | Select-Object -First 1}
Trace-CommandRestricted $expression consolehost,type,param
DEBUG: CommandDiscovery Information: 0 : Looking up command: Get-Process
DEBUG: CommandDiscovery Information: 0 : Cmdlet found: Get-Process Microsoft.PowerShell.Commands.GetProcessCommand
DEBUG: CommandDiscovery Information: 0 : Looking up command: Select-Object
DEBUG: CommandDiscovery Information: 0 : Cmdlet found: Select-Object Microsoft.PowerShell.Commands.SelectObjectCommand
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
63 3 908 80 33 1444 armsvc
Jan 13th
Reading the Windows PowerShell Language Specification Version 3.0 I stumbled upon curious example of variable splatting (listed in part 2.3.2 – Variables of the document) that I assumed shouldn’t work. The example partially defined Get-Power function that should raise the base number to the specified power. So I implemented the body of the function and tested how it works. And to my amezement It worked flawlessly. Here is the example function, and some calls to test if it works properly:
function Get-Power ($Base, $Exponent)
{
#return x^y
[Math]::Pow($Base,$Exponent)
}
#call normally by positioned parameters
Get-Power 5 3
# put arguments into an array and call with splatting
$values = 5,3
Get-Power @values
#call normally by named parameters
Get-Power -Base 5 -Exponent 3
# put arguments into a Hashtable and call with splatting
$hash = @{ exponent = 3; base = 5 }
Get-Power @hash
Until the PowerShell version 3 splatting the array (the first case) was equivalent only to calling the function with parameters by position, but not anymore, as shown in the second example. Splatting the hashtable remains equivalent to calling the function with named parameters.
Here is example of the new behavior. You define new function Get-PowerWrapper that calls the original function Get-Power by splatting the Args variable. The Args variable contains all arguments passed to the function in an array. The original command is called and the PowerShell ParameterBinding engine is inteligent enough to bind the correct items together (parameter Exponent to value 3), effectively calling the command with named parameters.
function Get-PowerWrapper { Get-Power @args } # arguments are in an array
Get-PowerWrapper –exponent 3 –base 2
Get-PowerWrapper –base 2 –exponent 3
In the example the positioning of the parametes varies but the result is still 8. In PowerShell version 2 the script would end with conversion type exception because the string ‘-exponent’ would be passed to parameter on position one in the called function (the parameter named Base – see the definition of the Get-Power function).
The change is quite subtle but it enables you to write quick wrappers for existing commands without reimplementing their interface (parameters). This is of course unsafe way to do it, and you cut yourself from code completion, but as prototyping tool it looks awesome.
function Get-ChildItemSafe {
if (Test-Path @args)
{
Get-ChildItem @args
}
}
Get-ChildItemSafe -Path C:\temp
Of course you have to use only the parameters that are common to all the commandlets called.
Note: Unfortunately I did not discovered how exactly the binding rules work, because creating an args-like array and splatting it to the command does not work - the names don't bind to the values correctly. But maybe it is a good thing because in that case you are better off defining appropriate hashtable to splat.