Recently one of our guests commented on the Navigation Pane in regards to removing the 3D Objects sub-directory, or renaming it for the purpose of storing personal files in.
For those of you familiar with Windows over the years, you will realize that what once was named My Computer was changed to be named Computer then in Windows 8 we saw a new name, that being This PC which Windows 10 also has.
The default sub-directories for This PC are:
At the time of writing this Article, there is no simple way to add your own sub-directories to This PC's list, as Microsoft had no intention of allowing this. Modifications will be made if a New Feature is added that requires an anchored shortcut, but other than that you are not supposed to play with this section of the Navigation Pane in File Explorer.
With regards to the Guest who wondered could they rename the 3D Objects sub-directory and use that folder to store their files. The answer is yes/no/not really.
That brings us to the question, 'Can we add our own sub-directory to the This PC list'?
One of our regular members, Norton, responded to this Guests question and provided a link to an interesting article by a former MVP for Microsoft Desktop environments, Ramesh Srinivasan. You can see that article here:
Having taken a look at the article I came to the conclusion it would be far easier for the average User to have a simple application to run, which does all the Registry and Directory creation for the User after they enter three pieces of information, then click a button.
Below is the PowerShell Script I've written, with full credits to those others out there for their ideas which has helped in creating this application.
Note: This is Version 1.0 [If you decide to try it, please post feedback for improvements or problems you have using the application].
The Code is commented for anyone interested in learning how it works.
So you do not have to muck around opening your PowerShell console, you will find attached a zipped folder.
Regedit32
For those of you familiar with Windows over the years, you will realize that what once was named My Computer was changed to be named Computer then in Windows 8 we saw a new name, that being This PC which Windows 10 also has.
The default sub-directories for This PC are:
- Desktop
- Documents
- Downloads
- Music
- Pictures
- Videos
Also, in a recent Feature update Microsoft added one additional sub-directory named 3D Objects.
At the time of writing this Article, there is no simple way to add your own sub-directories to This PC's list, as Microsoft had no intention of allowing this. Modifications will be made if a New Feature is added that requires an anchored shortcut, but other than that you are not supposed to play with this section of the Navigation Pane in File Explorer.
With regards to the Guest who wondered could they rename the 3D Objects sub-directory and use that folder to store their files. The answer is yes/no/not really.
- Yes, you could modify and rename the folder
- Yes you could place files into the folder
- However, this folder is here for Windows 10 3D applications like 3D Paint to store saved work etcetera, so its not really a good idea to try to use this sub-directory for anything else.
That brings us to the question, 'Can we add our own sub-directory to the This PC list'?
- Yes we can, but the process if done manually is rather lengthy and for some Users may be too complicated to bother trying as they will need to get information from their Registry, modify that information, then merge it into their Registry, then having done all that, create a folder, and finally, update the registry entry so as to point to their new sub-directory folder.
One of our regular members, Norton, responded to this Guests question and provided a link to an interesting article by a former MVP for Microsoft Desktop environments, Ramesh Srinivasan. You can see that article here:
Having taken a look at the article I came to the conclusion it would be far easier for the average User to have a simple application to run, which does all the Registry and Directory creation for the User after they enter three pieces of information, then click a button.
Below is the PowerShell Script I've written, with full credits to those others out there for their ideas which has helped in creating this application.
Note: This is Version 1.0 [If you decide to try it, please post feedback for improvements or problems you have using the application].
The Code is commented for anyone interested in learning how it works.
Code:
<#
__ ___ _ __ ___ ______
\ \ / (_) | | /_ |/ _ \| ____|
\ \ /\ / / _ _ __ __| | _____ _____| | | | | |__ ___ _ __ _ _ _ __ ___ ___ ___ ___ _ __ ___
\ \/ \/ / | | '_ \ / _` |/ _ \ \ /\ / / __| | | | | __/ _ \| '__| | | | '_ ` _ \/ __| / __/ _ \| '_ ` _ \
\ /\ / | | | | | (_| | (_) \ V V /\__ \ | |_| | | | (_) | | | |_| | | | | | \__ \| (_| (_) | | | | | |
\/ \/ |_|_| |_|\__,_|\___/ \_/\_/ |___/_|\___/|_| \___/|_| \__,_|_| |_| |_|___(_)___\___/|_| |_| |_|
PowerShell Script Repository: https://www.windows10forums.com/articles/this-pc-modifications.82/
Author: Regedit32
Date: 15 December 2017
Script: ThisPCModifier — Version 1.0
CREDIT: Chrissy LeMaire, MCC, MVP — https://gallery.technet.microsoft.com/scriptcenter/Export-Icon-from-DLL-and-9d309047
CREDIT: Thomas Levesque and darkfall
CREDIT: Ramesh Srinivasan — http://www.winhelponline.com/blog/add-custom-folder-this-pc-navigation-pane-windows/
CREDIT: Norton for pointing out Ramesh's Article
CREDIT: David Corrale — https://info.sapien.com/index.php/guis/gui-controls/spotlight-on-the-imagelist-control
#>
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.IO
Function ConfirmUserIsAdministrator {
[CmdletBinding()]
Param()
${CmdletName} = $Pscmdlet.MyInvocation.MyCommand.Name
${Identity} = [System.Security.Principal.WindowsIdentity]::GetCurrent()
${Principal} = new-object System.Security.Principal.WindowsPrincipal(${Identity})
${IsAdmin} = $Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not ${IsAdmin}) {
Write-Error -Message "${CmdletName}: User is not an administrator. To continue run application as administrator." `
-RecommendedAction "Run application as administrator"
Break
}
}
ConfirmUserIsAdministrator
Function FormOpened {
Return $true
}
Function ThisPCSubdirectory {
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT
# Variables to store User input
[String] $newSubdirectoryName = $txtBox1.Text
[String] $description = $txtBox2.Text
[String] $iconValue = $iconsView.SelectedIndices
# Obtain and store a unique guid
[String] $uniqueGUID = [guid]::NewGuid().ToString()
<# ### 1 ### #>
New-Item -Path "HKCR:\CLSID\" -Name "{$uniqueGUID}" -ItemType Directory -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}" -Name "(Default)" -PropertyType String -Value "(value not set)" -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}" -Name "DescriptionID" -PropertyType DWord -Value 0x00000003 -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}" -Name "Infotip" -PropertyType ExpandString -Value "@%SystemRoot%\system32\shell32.dll,-12690" -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}" -Name "System.IsPinnedToNameSpaceTree" -PropertyType DWord -Value 0x00000001 -Force | Out-Null
New-Item -Path "HKCR:\CLSID\{$uniqueGUID}\" -Name "DefaultIcon" -ItemType Directory -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\DefaultIcon" -Name "(Default)" -PropertyType ExpandString -Value "%SystemRoot%\System32\imageres.dll,-189" -Force | Out-Null
New-Item -Path "HKCR:\CLSID\{$uniqueGUID}\" -Name "InProcServer32" -ItemType Directory -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\InProcServer32" -Name "(Default)" -PropertyType ExpandString -Value "%SystemRoot%\System32\shell32.dll" -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\InProcServer32" -Name "ThreadingModel" -PropertyType String -Value "Both" -Force | Out-Null
New-Item -Path "HKCR:\CLSID\{$uniqueGUID}\" -Name "Instance" -ItemType Directory -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\Instance" -Name "CLSID" -PropertyType String -Value "{0E5AAE11-A475-4c5b-AB00-C66DE400274E}" -Force | Out-Null
New-Item -Path "HKCR:\CLSID\{$uniqueGUID}\Instance\" -Name "InitPropertyBag" -ItemType Directory -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\Instance\InitPropertyBag" -Name "Attributes" -PropertyType DWord -Value 0x00000011 -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\Instance\InitPropertyBag" -Name "TargetKnownFolder" -PropertyType String -Value "{35286a68-3c57-41a1-bbb1-0eae73d76c95}" -Force | Out-Null
New-Item -Path "HKCR:\CLSID\{$uniqueGUID}\" -Name "ShellFolder" -ItemType Directory -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\ShellFolder" -Name "Attributes" -PropertyType DWord -Value 0xf080004d -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\ShellFolder" -Name "FolderValueFlags" -PropertyType DWord -Value 0x00000029 -Force | Out-Null
New-ItemProperty -Path "HKCR:\CLSID\{$uniqueGUID}\ShellFolder" -Name "SortOrderIndex" -PropertyType DWord -Value 0x00000000 -Force | Out-Null
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\" -Name "{$uniqueGUID}" -ItemType Directory -Force | Out-Null
# Create directory to point to if one does not already exist
if ($storageDir.length -eq 0) {
$storageDir = "$env:HomeDrive\$newSubdirectoryName"
}
# Check whether directory exists. If not create it.
if ((Test-Path $storageDir) -eq $false) {
try {
New-Item -Type Directory $storageDir | Out-Null
}
catch {
throw "Can't create $storageDir"
}
}
UpdateRegistry
}
Function UpdateRegistry {
if ((Test-Path "HKCR:\CLSID\{$uniqueGUID}") -eq $true) {
try {
# Update Registry with User defined parameters
$regkey = "HKCR:\CLSID\{$uniqueGUID}"
Set-ItemProperty -Path $regkey -Name "(Default)" -Value $newSubdirectoryName -Force | Out-Null
Set-ItemProperty -Path $regkey -Name "Infotip" -Value "$description" -Force | Out-Null
Set-ItemProperty -Path "$regkey\DefaultIcon" -Name "(Default)" -Value "%SystemRoot%\System32\imageres.dll,$iconValue" -Force | Out-Null
Remove-ItemProperty -Path "$regkey\Instance\InitPropertyBag" -Name "TargetKnownFolder" -Force | Out-Null
New-ItemProperty -Path "$regkey\Instance\InitPropertyBag" -Name "TargetFolderPath" -PropertyType String -Value "$env:HomeDrive\$newSubdirectoryName" -Force | Out-Null
}
catch {
throw "HKCR:\CLSID\{$uniqueGUID} does not exist!"
}
}
Cleanup
}
# Clean up drive of temporary files and exit application
Function Cleanup {
# Close PSDrive
Remove-PSDrive -Name HKCR
# Remove temporary directory of extracted icons
Remove-Item -Path "$env:UserProfile\AppData\Local\Temp\Icons" -ErrorAction SilentlyContinue -Recurse
# Close Form
$form.Close()
}
# Cleanup if User closes Form
Function UserCancelCleanup {
# Remove temporary directory of extracted icons
rmdir -Path "$env:UserProfile\AppData\Local\Temp\Icons" -Recurse
$form.Close()
}
# Extract icons from imageres.dll
Function GetIcons {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$Path,
[string]$Directory,
[ValidateSet(32)]
[int]$Size = 32,
[ValidateSet("ico","bmp","png")]
[string]$Type = "ico"
)
Begin {
$code = '
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
namespace System {
public class IconExtractor {
public static Icon Extract(string file, int number, bool largeIcon) {
IntPtr large;
IntPtr small;
ExtractIconEx(file, number, out large, out small, 1);
try { return Icon.FromHandle(largeIcon ? large : small); }
catch { return null; }
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
}
}
public class PngIconConverter {
public static bool Convert(System.IO.Stream input_stream, System.IO.Stream output_stream, int size, bool keep_aspect_ratio = false) {
System.Drawing.Bitmap input_bit = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(input_stream);
if (input_bit != null) {
int width, height;
if (keep_aspect_ratio) {
width = size;
height = input_bit.Height / input_bit.Width * size;
}
else {
width = height = size;
}
System.Drawing.Bitmap new_bit = new System.Drawing.Bitmap(input_bit, new System.Drawing.Size(width, height));
if (new_bit != null) {
System.IO.MemoryStream mem_data = new System.IO.MemoryStream();
new_bit.Save(mem_data, System.Drawing.Imaging.ImageFormat.Png);
System.IO.BinaryWriter icon_writer = new System.IO.BinaryWriter(output_stream);
if (output_stream != null && icon_writer != null) {
icon_writer.Write((byte)0);
icon_writer.Write((byte)0);
icon_writer.Write((short)1);
icon_writer.Write((short)1);
icon_writer.Write((byte)width);
icon_writer.Write((byte)height);
icon_writer.Write((byte)0);
icon_writer.Write((byte)0);
icon_writer.Write((short)0);
icon_writer.Write((short)32);
icon_writer.Write((int)mem_data.Length);
icon_writer.Write((int)(6 + 16));
icon_writer.Write(mem_data.ToArray());
icon_writer.Flush();
return true;
}
}
return false;
}
return false;
}
public static bool Convert(string input_image, string output_icon, int size, bool keep_aspect_ratio = false) {
System.IO.FileStream input_stream = new System.IO.FileStream(input_image, System.IO.FileMode.Open);
System.IO.FileStream output_stream = new System.IO.FileStream(output_icon, System.IO.FileMode.OpenOrCreate);
bool result = Convert(input_stream, output_stream, size, keep_aspect_ratio);
input_stream.Close();
output_stream.Close();
return result;
}
}
'
Add-Type -TypeDefinition $code -ReferencedAssemblies System.Drawing, System.IO -ErrorAction SilentlyContinue
}
Process {
switch ($type) {
"jpg" { $type = "jpeg" }
"icon" { $type = "ico" }
}
# Ensure file exists
$path = Resolve-Path $path
if ((Test-Path $path) -eq $false) {
throw "$path does not exist."
}
# Ensure directory exists if one was specified. Otherwise, create icon directory in TEMP
if ($directory.length -eq 0) {
$directory = "$env:Temp\Icons"
}
if ((Test-Path $directory) -eq $false) {
try {
New-Item -Type Directory $directory | Out-Null
}
catch {
throw "Can't create $directory"
}
}
# Extract
$index = 0
$tempfile = "$directory\tempicon.png"
$basename = [io.path]::GetFileNameWithoutExtension($path)
do {
try {
$icon = [System.IconExtractor]::Extract($path, $index, $true)
}
catch {
throw "Could not extract icon. Do you have the proper permissions?"
}
if ($icon -ne $null) {
$filepath = "$directory\$basename-$index.$type"
# Convert to bitmap, otherwise it's ugly
$bmp = $icon.ToBitmap()
try {
if ($type -eq "ico") {
$bmp.Save($tempfile,"png")
[PngIconConverter]::Convert($tempfile,$filepath,$size,$true) | Out-Null
# Keep remove-item from complaining about weird directories
cmd /c del $tempfile
}
else {
if ($bmp.Width -ne $size) {
# Needs to be resized
$newbmp = New-Object System.Drawing.Bitmap($size, $size)
$graph = [System.Drawing.Graphics]::FromImage($newbmp)
# Make it transparent
$graph.clear([System.Drawing.Color]::Transparent)
$graph.DrawImage($bmp,0,0,$size,$size)
#save to file
$newbmp.Save($filepath,$type)
$newbmp.Dispose()
}
else {
$bmp.Save($filepath,$type)
}
$bmp.Dispose()
}
$icon.Dispose()
$index++
}
catch {
throw "Could not convert icon!"
}
}
} while ($icon -ne $null)
# Strip file name down to Value only
Dir $directory | Rename-Item -NewName { $_.Name -replace "imageres-","" }
}
}
# Create Form
Function GenerateForm {
# Echo message
Write-Host
Write-Host "Extracting icons . . ."
Write-Host
Write-Host ". . . Preparing Form . . ."
Write-Host
Write-Host " . . . This will take a moment . . ."
Write-Host
Write-Host " . . . Please wait . . ."
Write-Host
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(900,780)
$form.BackColor = 'CornflowerBlue'
$form.StartPosition = 'CenterParent'
$font = New-Object System.Drawing.Font("Sitka Small",18,[System.Drawing.FontStyle]::Regular)
# Get name for new subdirectory from User
$label = New-Object System.Windows.Forms.Label
$label.AutoSize = $true
$label.Location = New-Object System.Drawing.Size(15,15)
$label.Font = $font
$label.Text = "Enter name for new subdirectory:"
# Obtain New Subdirectory Name
$txtBox1 = New-Object System.Windows.Forms.TextBox
$txtBox1.Size = New-Object System.Drawing.Size(150,20)
$txtBox1.Location = New-Object System.Drawing.Size(450,15)
# Get description of new subdirectory from User
$label2 = New-Object System.Windows.Forms.Label
$label2.AutoSize = $true
$label2.Location = New-Object System.Drawing.Size(15,55)
$label2.Font = $font
$label2.Text = "Type a description of subdirectories content:"
$txtBox2 = New-Object System.Windows.Forms.TextBox
$txtBox2.Size = New-Object System.Drawing.Size(200,20)
$txtBox2.Location = New-Object System.Drawing.Size(590,55)
# Instruct User to select icon
$label3 = New-Object System.Windows.Forms.Label
$label3.AutoSize = $true
$label3.Location = New-Object System.Drawing.Size(25,120)
$label3.Font = $font
$label3.Text = "Select the icon you would like to use by left-clicking with mouse:"
$label3.TextAlign = 'BottomCenter'
# Generate Unique GUID and new Subdirectory
$button = New-Object System.Windows.Forms.Button
$button.AutoSize = $true
$button.Font = $font
$button.Text = "Click to create unique guid and generate new Subdirectory"
$button.TextAlign = "BottomCenter"
$button.Enabled = $true
$button.FlatStyle = "Flat"
$button.Location = New-Object System.Drawing.Size(63,600)
$button.BackColor = 'Black'
$button.ForeColor = 'Gold'
# Action on Click
$button.Add_Click({ ThisPCSubdirectory })
# Cancel / Close Form
$button2 = New-Object System.Windows.Forms.Button
$button2.AutoSize = $true
$button2.Font = $font
$button2.Text = "Cancel / Close"
$button2.TextAlign = "BottomCenter"
$button2.Enabled = $true
$button2.FlatStyle = "Flat"
$button2.Location = New-Object System.Drawing.Size(63,680)
$button2.BackColor = 'Black'
$button2.ForeColor = 'Gold'
#Action on Click
$button2.Add_Click({ UserCancelCleanup })
# ListView for Icons Choice
$iconsView = New-Object System.Windows.Forms.ListView
$iconsView.Size = New-Object System.Drawing.Size(855,400)
$iconsView.Location = New-Object System.Drawing.Size(15,160)
$iconsView.BackColor = 'Sienna'
# Extract Icons from imageres.dll
GetIcons "$env:WinDir\System32\imageres.dll"
# Create ImageList
$iconsList = New-Object System.Windows.Forms.ImageList
# Add icons to ImageList
[int] $i = 0
do {
$iconsList.Images.Add([System.Drawing.Image]::FromFile("$env:UserProfile\AppData\Local\Temp\Icons\$i.ico"))
$i++
} while ($i -lt 412)
# Associated iconsList with ListView
$iconsView.LargeImageList = $iconsList
$iconsView.LargeImageList.ImageSize = [System.Drawing.Size] '32,32'
$iconsView.LargeImageList.ColorDepth = '32'
# Generate ListView text of imageres.dll icon Values
[int] $j = 0
do {
$iconsView.Items.Add("$j") | Out-Null
$j++
} while ($j -lt 412)
# Generate imageres.dll icons correlating to icon Value
[int] $k = 0
do {
$iconsView.Items[$k].ImageIndex = $k
$k++
} while ($k -lt 412)
# Set Form's icon and title
$form.Icon = "$env:UserProfile\AppData\Local\Temp\Icons\311.ico"
$form.Text = "ThisPC Subdirectory Generator — Regedit32 @ https://www.windows10forums.com/"
$form.Controls.AddRange(
($label, $label2, $label3, $txtBox1, $txtBox2,
$txtBox3, $txtBox4, $iconsView, $button, $button2))
# Prevent User being able to close Form
$form.ControlBox = $false
Return $form.ShowDialog()
}
if (FormOpened -eq $true) {
# Generate the Form
GenerateForm | Out-Null
}
So you do not have to muck around opening your PowerShell console, you will find attached a zipped folder.
- Download ThisPCModifier.zip
- Right-click on it and select Extract all
- You'll now see the executable file: ThisPCModifier.exe
- Right-click on this exe file and select Run as administrator
- You'll now see a elevated command console
- After 10 seconds the form will open and you can create your own sub-directories and add [ if you wish ] a description to appear in the information bubble that pops up when you hover your mouse over the folder.
- When all is done, the program will clean up the temporary files created, then close the Form.
- Right-click on this exe file and select Run as administrator
Regedit32