Trying to compare list of shortcuts on one machine to saved list

Basically what I want to create is a PowerShell script to compare the applications included in an OEM install of Windows 10 against those included in a clean install of Windows 10 and copy any application links which aren’t on a clean install to a specific folder so that I can easily see which apps have been added by the OEM.

I’ve figured out how to get a list of which applications have links on the Start Menu:

$Path = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs"
Get-ChildItem $Path -Recurse -Include *.lnk

And I’ve figured out how to assign that to an array:

$a = Get-ChildItem $Path -Recurse -Include *.lnk

Or how to copy that list of shortcuts to a folder:

Get-ChildItem $Path -Recurse -Include *.lnk | Copy-Item -Destination C:\temp\

Or save the list to a CSV:

Get-ChildItem $Path -Recurse -Include *.lnk | Export-Csv list.csv

And how to assign a CSV to an array:

$b = Import-Csv list.csv

And how to compare two arrays:

Compare-Object $a $b

But this is where I get stuck. I want to be able to do this:

Run this on a computer with no 3rd party apps, only a clean Windows 10 install:

$Path = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs"           
Get-ChildItem $Path -Recurse -Include *.lnk | Export-Csv cleaninstallapps.csv

Then take the cleaninstallapps.csv and copy it to a computer with 3rd party apps on it and get a list of only the apps which are not part of a clean Windows 10 install. And then copy links to those apps to a folder by doing this:

$Path = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs”
Get-ChildItem $Path -Recurse -Include *.lnk | | Export-Csv oeminstallapps.csv
$a = Import-Csv oeminstallapps.csv
$b = Import-Csv cleaninstallapps.csv
Compare-Object $a $b | Copy-Item –Destination C:\OEM_Programs

Everything works up until it gets piped to Copy-Item. Something is lost that doesn’t stop Compare-Object from working but does stop me from successfully piping that to Copy-Item. Any ideas for how to accomplish this task?

Hi,
Copy-Item copies files and folders, not arrays, I suggest using Export-Csv again instead.
Checking Start Menu for installed programs is not a good way to go, programs doesn´t need to have start menu shortcuts. This might be a good read: Use PowerShell to Quickly Find Installed Software

I find the compare-object confusing.

$a = (1…10)
$b = (1…15)
$b | ? {$_ -notin $a}

Erik, thanks for the article. I should be a little more clear about my purpose. I want to easily test the functionality of any application a user would be likely to open which isn’t part of a clean Windows 10 install. That’s why I’m checking for shortcuts rather than all installed programs and also why I want to create a folder with shortcuts to those programs. What I want is for a tester to be able to run a script on a device which opens up a folder with all of the non clean install programs in it so he can easily open and test each of them.

Dan, I like that code. I’ll use that instead of Compare-Object.

It does have it’s uses. You can do compare $a $b -IncludeEqual | ? {$_.sideindicator -eq ‘=>’}

When dealing with large similar arrays I get confused as to whether I compared fruit to vegetables or vegetables to fruit. The greatthan lessthan signs aren’t good indicators for my brain to process:D

Like I said earlier, Copy-Item can´t copy an array, when you export and then import from csv you loose the objects that you got from Get-ChildItem. If you skip that step and use Where-Object to filter your objects you´ll get what you want, something like:

$Path = "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs”
$a = Get-ChildItem $Path -Recurse -Include *.lnk
$b = Import-Csv cleaninstallapps.csv
$a | Where-Object {$_.name -notin $b.name} | Copy-Item –Destination C:\OEM_Programs

Also, if some of the file names from the clean install contains special characters you need to use the -Encoding parameter for both Export-Csv and Import-Csv (example: Import-Csv -Encoding UTF8 cleaninstallapps.csv) else the imported file names will contain ? as a replacement for every special character.

That worked perfectly! Thank you very much for helping me with this and taking the time to explain what I was doing wrong!