A quicky
Hyper-V clustered hosts. Storage of some VMs migrated from one host to another. On rare occasions migration failed. Reason is now irrelevant. But after this – there are some empty folders left on Clustered Shared Volumes:
├───Planned Virtual Machines
├───Snapshots
├───Virtual Hard Disks
└───Virtual Machines
There are also other situation where there are bunch of empty folders left (testing, installations, migrations etc).
I was looking for a neat solution and found this post by Jeffery Hicks – Link.
After a few minutes I’ve got a working function that:
- Can query local system
- Can query remote system (using Invoke-Command)
- Can use Credential parameter for remote sessions
- And thanks to the above – works also from PS Core:)
Here’s the code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-EmptyFolder { | |
<# | |
.SYNOPSIS | |
Returns if there are empty folders in given path. | |
.DESCRIPTION | |
Will check for empty folders in given path. If ComputerName is provided will connect to remote computer. Credential parameter works in combination with ComputerName only | |
.PARAMETER Path | |
Path to check for empty folders | |
.PARAMETER ComputerName | |
Remote computer name | |
.PARAMETER Credential | |
Credentials for remote computer | |
.EXAMPLE | |
Get-EmptyFolder -path 'c:\AdminTools','C:\Program Files' -ComputerName Server1 -Verbose | |
VERBOSE: Processing with remote computer {Server1} | |
VERBOSE: Processing with default credentials of user {mczerniawski_admin} | |
Directory: C:\AdminTools | |
Mode LastWriteTime Length Name PSComputerName | |
—- ————- —— —- ————– | |
d—– 05.11.2018 14:35 VMs Server1 | |
.EXAMPLE | |
Get-EmptyFolder -path 'c:\AdminTools','C:\Program Files' -Verbose | |
VERBOSE: Processing local computer {MyMachine1} | |
Directory: C:\AdminTools | |
Mode LastWriteTime Length Name | |
—- ————- —— —- | |
d—– 26.11.2018 15:49 1 | |
#> | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory, HelpMessage = 'Path to check', Position = 0, | |
ValueFromPipelineByPropertyName)] | |
[string[]] | |
$Path, | |
[Parameter(Mandatory = $false, HelpMessage = 'Provide Computer Name', | |
ValueFromPipelineByPropertyName)] | |
[ValidateNotNullOrEmpty()] | |
[System.String] | |
$ComputerName, | |
[Parameter(Mandatory = $false, HelpMessage = 'Provide Credentials for ComputerName', | |
ValueFromPipelineByPropertyName)] | |
[System.Management.Automation.PSCredential] | |
$Credential | |
) | |
begin { | |
$localExecution = $true | |
#region PSSession parameters | |
if ($PSBoundParameters.ContainsKey('ComputerName')) { | |
$connectionParams = @{ | |
ComputerName = $ComputerName | |
} | |
Write-Verbose -Message "Processing with remote computer {$ComputerName}" | |
if ($PSBoundParameters.ContainsKey('Credential')) { | |
$connectionParams.Credential = $Credential | |
Write-Verbose -Message "Processing with provided credentials {$($Credential.UserName)}" | |
} | |
else { | |
Write-Verbose -Message "Processing with default credentials of user {$($env:USERNAME)}" | |
} | |
$localExecution = $false | |
} | |
else { | |
Write-Verbose -Message "Processing local computer {$($env:COMPUTERNAME)}" | |
} | |
#endregion | |
} | |
process { | |
if ($localExecution) { | |
Get-ChildItem -Path $Path | Where-Object -FilterScript {$PSItem.PSIsContainer -eq $True} | Where-Object -FilterScript {-NOT $_.GetFiles("*", "AllDirectories")} | |
} | |
else { | |
Invoke-Command @connectionParams -ScriptBlock { | |
Get-ChildItem -Path $USING:Path | Where-Object -FilterScript {$PSItem.PSIsContainer -eq $True} | Where-Object -FilterScript {-NOT $_.GetFiles("*", "AllDirectories")} | |
} | |
} | |
} | |
} |
And here’s the output:
-
Local run:
-
Remote run with credential parameter