Yes, the whole point is to further your understanding of PowerShell.
The use of the line
robocopy $FolderPath NULL /L /E /MT:128 /FP /NP /TEE /NJH /NJS /NC /NDL /R:0 /W:0 /XJ /BYTES
outputs the file size in bytes, and the full file name
This output is then piped to one or more lines to parse that text output of robocopy.exe to extract the Name,Extension,Fullname,CreationTime,LastAccessTime,FileSize properties you want.
What’s missing in the robocopy.exe output is the creationtime and lastaccesstime perperties.
I admit that the expression
$PSItem.Substring($PSItem.IndexOf(':') - 1 , $PSItem.Length - $PSItem.IndexOf(':') + 1)
is complex and not optimal for learning. But the idea is simple. Robocopy returns a line of text for each file that looks like:
12345 c:\bla1\bla 2\bla.3\bla4.txt
You need to parse out file name, extension, and full name. You have to account for possible multiple spaces and multiple dots (but a single colon)
if
$a = ' 12345 c:\bla1\bla 2\bla.3\bla4.txt'
then
$a.Split(':')
will return
12345 c
\bla1\bla 2\bla.3\bla4.txt
The colon is an attractive marker for parsing here because you can be assured that there can be only one colon in a file name
The .Split() method will provide an array of 2 elements.
The second one is the file full name less the colon and the drive letter which is the last letter of the first split string.
So,
$a.Split(':')[1]
returns the 2nd element of that .Split() array of text (array elements are counted starting from 0)
\bla1\bla 2\bla.3\bla4.txt
The last letter of the first .Split() array element can be referenced as
$a.Split(':')[0][-1]
This may be a little complicated, but simply put
$a.Split(':')[0]
returns the first string of characters being the first .Split() array element
12345 c
which is in itself an array of characters. The last array element can be refereed to by [-1]
So, to stitch this expression together, the file full name can be parsed as:
"$($a.Split(':')[0][-1]):$($a.Split(':')[1])"
What this expression does is to concatenate the last character before the colon + the colon + the rest of the characters after the colon
Once we have file full name as in
$FileFullName = "$($a.Split(':')[0][-1]):$($a.Split(':')[1])"
We can get the file name by using:
$FileName = Split-Path $FileFullName -Leaf
Using similar parsing techniques, we can demo parsing a line like:
$a = ' 12345 c:\bla1\bla 2\bla.3\bla4.txt'
$FileFullName = "$($a.Split(':')[0][-1]):$($a.Split(':')[1])"
$FileName = Split-Path $FileFullName -Leaf
$Extension = $FileName.Substring($FileName.LastIndexOf('.') , $FileName.Length - $FileName.LastIndexOf('.'))
[Int]$FileSize = ($a.Split(':')[0][0..($a.Split(':')[0].Length -2)] -join '').Trim()
"If the string is '$a'"
"FileFullName is '$FileFullName'"
"FileName is '$FileName'"
"Extension is '$Extension'"
"Size (bytes) is '$FileSize' bytes"
In the original expression $PSItem or $_ refers to the text line being passed to the pipeline from robocopy.exe
Putting the parsed output in a more manageable PS object:
$FolderPath = 'D:\Sandbox'
$Results = robocopy $FolderPath NULL /L /E /MT:128 /FP /NP /TEE /NJH /NJS /NC /NDL /R:0 /W:0 /XJ /BYTES | foreach {
$FileFullName = "$($PSItem.Split(':')[0][-1]):$($PSItem.Split(':')[1])"
$FileName = Split-Path $FileFullName -Leaf
[Int]$FileSize = ($PSItem.Split(':')[0][0..($PSItem.Split(':')[0].Length -2)] -join '').Trim()
[PSCustomObject][Ordered]@{
Name = $FileName
Extension = $(
if ($FileName -match '\.') { # this if statement accounts for files with no extension
$FileName.Substring($FileName.LastIndexOf('.') , $FileName.Length - $FileName.LastIndexOf('.'))
} else {
'None'
}
)
FullName = $FileFullName
'Size(GB)' = [Math]::Round($FileSize / 1GB , 2)
}
}
$Results | FL
What’s missing here is the CreationTime and LastAccessTime, can you lookup robocopy documentation to see if there are switches to show those?