Skip to content

Instantly share code, notes, and snippets.

@chklauser
Created July 22, 2012 19:23
Show Gist options
  • Save chklauser/3160775 to your computer and use it in GitHub Desktop.
Save chklauser/3160775 to your computer and use it in GitHub Desktop.
PowerShell script to make ~\Documents more usable, hides directories and makes them accessible via a symlink in a different location.
param(
[Parameter(Position=0)]
$Item,
[Switch] $WhatIf,
[String] $AppConfig = "$env:HOMEDRIVE$env:HOMEPATH\AppConfig",
[String] $BaseDir = ".",
[Parameter(ParameterSetName="register")]
[Switch]
$Register,
[Parameter(ParameterSetName="unregister")]
[Switch]
$Unregister);
# Clean up your ~, and ~\Documents directories on Windows while not breaking any of the applications that use it
# Usage: .\Manage-AppConfig.ps1 -Register Documents\SomeStupidApp
# Will
# - create a symlink to Documents\SomeStupidApp in ~\AppConfig\Documents\SomeStupidApp
# - hide Documents\SomeStupidApp
#
# You can configure ~\AppConfig to be something different, I wouldn't necessarily use ~\AppData, though because I have seen programs that use BOTH locations :-(
# By default the path under ~\AppConfig is the same as the path you specified (MUST be relative), but you can also explicitly specify the BasePath.
#
# Provided AS IS. It might not work. It might break something and destroy 5 years of your hard work in 5 seconds, or less.
$ErrorActionPreference = "stop";
Write-Debug "Item: $Item";
Write-Debug "BaseDir: $BaseDir";
Write-Debug "AppConfig: $AppConfig";
$WhatIfPreference = $WhatIf;
function Get-Attributes($Path){
(Get-Item -Path $Path).Attributes
}
function Hide-File($Path){
$i = Get-Item $Path -Force;
if(-not ($i.Attributes -match "Hidden")){
$i.Attributes = @("Hidden") + $i.Attributes;
}
}
function Unhide-File($Path){
$i = Get-Item $Path -Force;
Write-Debug "unhiding: $($i.Attributes)";
if($i.Attributes -match "Hidden"){
$n = [IO.FileAttributes]($i.Attributes -bxor [IO.FileAttributes]::Hidden)
Write-Debug "newattributes: $n"
$i.Attributes = $n;
}
}
if(-not (Test-Path $AppConfig)){
Write-Debug "AppConfig at $AppConfig does not exist. Creating it now."
New-Item $AppConfig -ItemType "directory";
}
function Check-Status($Path){
$AbsolutePath = [System.IO.Path]::GetFullPath((Join-Path $BaseDir $Path));
if(-not (Test-Path $AbsolutePath)){
Write-Debug "Cannot find item to manage: $AbsolutePath"
throw "Cannot find item to manage: $AbsolutePath";
}
$Item = Get-Item $Path -Force; # -Force because hidden items will not be found otherwise
$MirrorPath = [System.IO.Path]::GetFullPath((Join-Path $AppConfig $Path));
if(Test-Path $MirrorPath){
Write-Debug "Mirror $MirrorPath exists";
$mirror = Get-Item $MirrorPath;
if([bool]((Get-Attributes $MirrorPath) -band [System.IO.FileAttributes]::ReparsePoint)){
Write-Debug "Mirror $MirrorPath is a reparse point";
if($mirror.ReparsePoint.Target -eq $Item.FullName){
Write-Debug "Mirror $MirrorPath already points to $Item.";
$status = "exists";
} else {
Write-Debug "Mirror $MirrorPath points to different item $($mirror.ReparsePoint.Target)";
$status = "conflicting";
}
} else {
Write-Debug "Found ordinary file/directory in mirror at $mirror.";
$status = "invalid";
}
} else {
Write-Debug "Mirror $MirrorPath does not exist (yet)."
$status = "none";
}
}
$visibilityAction = "none";
switch($PsCmdlet.ParameterSetName){
"register" {
Write-Debug "Register $Item into AppConfig at $AppConfig.";
. Check-Status $Item
switch ($status){
"exists" {
Write-Verbose "Correct mirror already exists at $MirrorPath.";
$visibilityAction = "hide";
break;
}
"invalid" {
Write-Error "Ther mirror's location is occupied by a different item: $mirror (not a reparse-point)";
break;
}
"conflicting" {
Write-Error "There is already a mirror in place pointing at a different location: $($mirror.ReparsePoint.Target)";
break;
}
"none" {
Write-Verbose "Installing mirror from $MirrorPath to $Item.";
$fp = [System.IO.Path]::GetFullPath($MirrorPath);
if($WhatIf){
Write-Host "Creating symlink from $fp to $Item.";
} else {
Write-Debug "fp=$fp";
New-Item -ItemType "directory" -Force ([IO.Path]::GetDirectoryName($fp))
New-Symlink "$fp" -TargetPath "$Item";
}
$visibilityAction = "hide";
break;
}
default {
Write-Error "Unknown state.";
break;
}
}
break;
}
"unregister" {
Write-Debug "Unregister $Item from AppConfig at $AppConfig.";
. Check-Status $Item
switch ($status){
"exists" {
Write-Verbose "Expected mirror found at at $MirrorPath. Removing it.";
if($Whatif){
Write-Host "Removing reparse point at $MirrorPath.";
} else {
Remove-ReparsePoint "$MirrorPath";
}
$visibilityAction = "show";
break;
}
"invalid" {
Write-Error "Ther mirror's location is occupied by a different item: $mirror";
break;
}
"conflicting" {
Write-Error "The mirror points at a different location than expected: $($mirror.ReparsePoint.Target)";
break;
}
"none" {
Write-Verbose "No mirror found at $MirrorPath.";
$visibilityAction = "show";
break;
}
default {
Write-Error "Unknown state.";
break;
}
}
break;
}
}
switch($visibilityAction){
"show" {
Write-Verbose "Un-hiding $Item";
Unhide-File $Item;
break;
}
"hide" {
Write-Verbose "Hiding $Item";
Hide-File $Item;
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment