@{...=...; ...=...} é uma hashtable . Você pode conhecê-los como "dicionários" em outros idiomas. Estes são pares chave / valor. Os pontos-e-vírgulas ( ; ) separam os diferentes pares, e a chave e o valor são separados por um sinal de igual ( = ). Note que a chave pode ter citações implícitas, tornando-a uma string.
A parte { "{0:N0}" -f ($_.Length / 1KB) } é um bloco de script . Há um monte desses; todas as chaves Expression nas tabelas de hash são mapeadas para uma. Você pode dizer isso pelas chaves sem um prefixo em torno dele. Estas são essencialmente funções anônimas (lambdas). O $_ é o item atual do pipeline, portanto, quando esse bloco de script é executado, ele é expandido para um único item a partir da entrada do pipeline.
O bloco de script em particular "{0:N0}" -f ($_.Length / 1KB) part está apenas usando o % operador de-f para fazer a formatação . Isso equivale ao String.Format do .NET, onde a cadeia padrão está à esquerda e os argumentos para o padrão são uma matriz de objetos à direita. O 0 é apenas o índice do argumento (portanto, primeiro argumento) e o :N0 indica que ele deve ser formatado como um número com 0 casas decimais.
Agora, entre todas as hashtables, temos um monte de vírgulas. Isso cria uma matriz ! Acontece que a parte @(...) circundante é opcional.
Portanto, temos um array contendo algumas strings e um monte de hashtables com as chaves Name e Expression , e esse array é um argumento sendo passado para Select-Object . Ou seja, é o argumento -Property . Observe esta linha do doc do SS64:
To add a calculated property to an object, specify a hash table as a value of the -Property parameter. The hash table must include two keys: Name and Expression with the Expression key assigned a script block that will determine the value of the property.
Então tudo isso faz um pouco mais de sentido agora. É apenas Select-Object transformando a entrada, e está reunindo vários atributos "calculados" (determinados pelo bloco de scripts) e um atributo "não calculado" (já presente no objeto de entrada) para o objeto de saída.
Uma pequena nota: acredito que este atributo calculado em particular é um tanto bobo:
@{Name="LastWriteTime";Expression={$_.LastWriteTime}}
Não vejo nenhum motivo para que ele não tenha sido selecionado diretamente como Name .