How To Join Object Lists In PowerShell

Question

So I have these two arrays of data objects in my PowerShell code:

$Customers = (
    @{ Id = 1; Name = "Customer 1" },
    @{ Id = 2; Name = "Customer 2"; },
    @{ Id = 3; Name = "Customer 3"; }
);

$Orders = (

    @{ Id = 1; CustomerId = 1; Product = "Red Pumpkin" },
    @{ Id = 2; CustomerId = 1; Product = "Blue Pumpkin" },
    @{ Id = 3; CustomerId = 2; Product = "Green Pumpkin" }
);

How can I mimic a SQL-like JOIN on these two lists and output a new list with the joined data?

Short Answer

Looping and New-Object are your friends:

# loop all customers
foreach ($c in $Customers)
{
    # loop al orders
    foreach ($o in $Orders)
    {
        # decide whether to join
        if ($o.CustomerId -eq $c.Id)
        {
            # output a new object with the join result
            New-Object PSObject -Property @{
                CustomerId = $c.Id;
                OrderId = $o.Id;
                CustomerName = $c.Name;
                OrderProduct = $o.Product;
            };
        }
    }
}

What would be really cool though would be to have a CmdLet that would do this work for us dynamically whilst allowing us to pipe data through, wouldn’t it?

Continue reading “How To Join Object Lists In PowerShell”

How To Access .NET Property Types Dynamically In PowerShell

Question

So I have this given list of objects. I don’t know their structure beforehand. I want to be able to access their property values and underlying data types to accomplish some other task.

Here is some dummy data as an example:

$DataList = (
    @{ Id = 1; Name = "Red Pumpkin" },
    @{ Id = 2; Name = "Green Pumpkin" },
    @{ Id = 3; Name = "Blue Pumpkin" }
) | %{ New-Object PSObject -Property $_ };

How do I do this?

Continue reading “How To Access .NET Property Types Dynamically In PowerShell”

How To Find And Remove Old Files In PowerShell

Question

So I have all these files in my backup folder. How can I keep only the files modified at most seven days ago, whilst removing the rest?

Short Answer

We can use a simple chain like this:

Get-ChildItem -Recurse |

    # change the extension as appropriate
    ?{ $_.Extension -eq ".bak" } |

    # change the time window as appropriate
    ?{ $_.LastWriteTime -lt (Get-Date).AddDays(-7) } |

    # now remove the results
    Remove-Item

We can then add or remove filters to this pattern as appropriate to your scenario.

So what more stuff can we add?

Continue reading “How To Find And Remove Old Files In PowerShell”

PowerShell: Break, Return Or Exit?

Question

What is the difference between the keywords Exit, Return and Break in PowerShell?
What does each exactly do?

Short Answer

  • Break terminates execution of a loop or switch statement and hands over control to next statement after it.
  • Return terminates execution of the current function and passes control to the statement immediately after the function call.
  • Exit terminates the current execution session altogether. It also closes the console window and may or may not close ISE depending on what direction the wind is facing.

Not sure I get it yet…
Can you provide some examples?

Sure thing, let’s look at an example for each one.

Continue reading “PowerShell: Break, Return Or Exit?”

How To Edit The Windows Registry In PowerShell

Question

How can I access the Windows Registry in PowerShell so I can create, update and delete keys and values?

Short Answer

Use the Get-ItemProperty and Set-ItemProperty Cmdlets:

# get the data from a specific registry key value
Get-ItemProperty "HKLM:\SOFTWARE\MyRegistryKey" |
    % { $_.MyKeyValue };

# set the data for a specific registry key value
Set-ItemProperty "HKLM:\SOFTWARE\MyRegistryKey" -Name "MyKeyValue" -Value "Some Data";

Long Answer

When playing with the Windows Registry, the common Item Cmdlets are our friends:

Continue reading “How To Edit The Windows Registry In PowerShell”

How To Gracefully Stop An Asynchronous Job In PowerShell

Question

How can we ask an asynchronous PowerShell job to gracefully stop on its own?

Short Answer

We can use a marker file pattern for that effect:

# this is the path to the marker file
$JobStopMarkerFile = "C:\Temp\JobStopMarker.txt";

# ensure the marker file does not exist
if (Test-Path -LiteralPath $JobStopMarkerFile)
{
    Remove-Item $JobStopMarkerFile
}

# this contains the script to run async
$JobScript = {

    param
    (
        [Parameter(Mandatory = $true)]
        $JobStopMarkerFile
    )

    # this flag will be set when the job is done
    $IsJobDone = $false

    # this condition checks whether
    # 1) the job is done
    # 2) the job has been asked to stop
    while (-not $IsJobDone)
    {
        # some recurring task would run here instead
        Start-Sleep -Seconds 5

        # uncomment and set this whenever the job finishes on its own
        # $IsJobDone = $true

        # check if the marker file exists
        if (Test-Path -LiteralPath $JobStopMarkerFile)
        {
            # signal the job as completed
            $IsJobDone = $true;

            # cleanup the file too
            Remove-Item -LiteralPath $JobStopMarkerFile
        }
    }
}

# start the job now
$Job = Start-Job -ScriptBlock $JobScript -ArgumentList $JobStopMarkerFile

# do some other stuff here
Start-Sleep 1

# ask the job to stop
# we do this by *creating* an empty marker file
# the job itself will remove this file
$null > $JobStopMarkerFile

# wait for the job to finish
Wait-Job $Job

There is quite some code here, isn’t there? So how does it work?

Long Answer

If we just want to stop a job, minus the gracefully bit, we can simply use the Stop-job Cmdlet:

Continue reading “How To Gracefully Stop An Asynchronous Job In PowerShell”

How To Discover The Installed Version Of PowerShell

Question

How can we discover which version of PowerShell we are running on?

Quick Answer

We can use the $PSVersionTable system variable:

$PSVersionTable.PSVersion

This will return an object with the installed version build numbers:

PowerShell Installed Version

Long Answer

We can use $PSVersionTable to discover the versions of different components of PowerShell:

Continue reading “How To Discover The Installed Version Of PowerShell”

How To Uninstall An Application In PowerShell

Question

How can we uninstall an application listed in Programs and Features using PowerShell?

Short Answer

We can use the Win32_Product WMI class.

$app = Get-WmiObject
    -Class Win32_Product
    -Filter "Name = 'Application Name'"
$app.Uninstall()

Long Answer

We can use the Win32_Product WMI class to query the system for installed applications.

Continue reading “How To Uninstall An Application In PowerShell”

PowerShell: Warming Up

So you’ve decided to learn PowerShell? Then we’re on the same boat, you and I!

While I have been playing around with PowerShell for a bit now and for a variety of different purposes, I have yet to sit down and learn the details from the very beginning. PowerShell may have a relatively easy learning curve but relying on your existing knowledge of the .NET Framework will only take you so far.

In this series, I’m going to start the process of learning PowerShell from the ground up, exploring the details that make this great tool such a pleasure to play with.

Continue reading “PowerShell: Warming Up”

How To Easily Loop And Index In PowerShell

Just learned these bits today while trying to answer something and thought to share them.

Consider these two arrays:

$x = @("a","b","c","d");
$y = @("apple","banana","carrot","dinner");

What I want to see as output is:

a is for apple
b is for banana
c is for carrot
d is for dinner

There are a couple of ways of going about this and then some.

You can use a regular for loop:

for ($i = 0; $i -Lt $x.Count; ++$i)
{
    "$($x[$i]) is for $($y[$i])";
}

You can go with a regular foreach loop too this way, if the values in $x are distinct – we’ll get around that in a second:

foreach ($v in $x)
{
    "$v is for $($y[$x.IndexOf($v)])"
}

You can shorten it by using a ForEach-Object CmdLet:

$x | ForEach-Object { "$_ is for $($y[$x.IndexOf($_)])" };

You can shorten the ForEach-Object into the % operator:

$x | % { "$_ is for $($y[$x.IndexOf($_)])" };

And finally, you can fix the issue of indexing duplicates by adding an initializer to the foreach and treating it just like a for:

$x | % { $i = 0 } { "$_ is for $($y[$i])"; ++$i };

You learn something new every day.


Index: PowerShell HowTo’s