#powershell
#powershell
Вопрос:
Всем доброго утра!
Я возился с оператором switch с тех пор, как узнал об этом в другом сообщении, которое я сделал.
У меня есть эта проблема с приведенным ниже кодом, где он печатает несколько строк с одной и той же информацией, и я понимаю, почему это так, но я не знаю, как это исправить. Я считаю, что это неправильно, когда я присваиваю переменную, но я не слишком уверен. Может ли кто-нибудь указать мне правильное направление в том, что может быть причиной проблемы? Любая помощь приветствуется.
$gc = Get-ChildItem -Path 'C:usersabrahOneDriveDesktop'
Foreach ($File in $gc) {
switch -Wildcard ($file) {
"deskt*" { $Desk = "This is the location: $($File.FullName)" }
"*v*" { $VA = "This is the location: $($File.FullName)" }
}
$VCount = $va | Measure-Object | Select-Object -ExpandProperty Count
$Dcount = $Desk | Measure-Object | Select-Object -ExpandProperty Count
$PS = [pscustomobject]@{
DesktopLocation = $Desk
DCount = $Dcount
VLocation = $VA
VCount = $VCount
}
$PS
}
О скрипте: я просто ищу, чтобы найти любые файлы на моем рабочем столе, которые начинаются с deskt
, и любые с буквой V
в нем. Затем я помещаю ее в пользовательский объект, пытаясь подсчитать, сколько файлов содержат эти ключевые буквы.
Вот результаты, кстати:
Комментарии:
1. Я также подумал: «Может быть, я могу просто посчитать элементы в customobject, но тогда как я буду добавлять к нему?»
2. Вы продолжаете пытаться «пересчитать» все каждый раз, когда работаете с одним файлом прямо сейчас. Делайте что-то одно за раз, и это будет намного проще
Ответ №1:
Что касается подхода, основанного на вашем switch
заявлении:
switch
сам по себе способен обрабатывать коллекции, поэтому нет необходимости заключать его вforeach
цикл.- То, что вы ищете, — это создать две коллекции из входных данных, что требует от вас:
- инициализировать
$Desk
и$VA
как тип данных коллекции. - добавьте к этим коллекциям в обработчиках
switch
ветвей.
- инициализировать
# Initialize the collections.
$Desk = [System.Collections.Generic.List[string]] @()
$VA = [System.Collections.Generic.List[string]] @()
# Make `switch` loop over the .FullName values of all items in the target dir.
switch -Wildcard ((Get-ChildItem C:usersabrahOneDriveDesktop).FullName) {
'*deskt*' { $Desk.Add("This is the location: $_") } # add to collection
'**v*' { $VA.Add("This is the location: $_") } # add to collection
}
# Construct and output the summary object
[pscustomobject] @{
DesktopLocation = $Desk
DCount = $Desk.Count
VLocation = $VA
VCount = $VA.Count
}
Примечание:
- Хотя в качестве типа коллекции можно использовать массив, «добавление» к массивам с
=
помощью, хотя и удобно, неэффективно, поскольку каждый раз новый массив должен создаваться за кулисами, учитывая, что массивы неизменяемы в отношении количества их элементов.
Хотя это может не иметь значения для массивов, содержащих всего несколько элементов, это хорошая привычка для формирования, чтобы использоватьSystem.Collections.Generic.List`1
ее в качестве эффективно расширяемого типа коллекции. - Тем не менее, учитывая, что такие операторы, как
switch
иforeach
циклы, могут действовать как выражения при назначении переменной, если весь вывод должен быть записан в одну коллекцию, вам даже не нужен тип коллекции явно, который является кратким и эффективным; например:
$collection = foreach ($i in 0..2) { $i 1 }
сохраняет массив1, 2, 3
в$collection
; обратите внимание, что если выводится только один объект,$collection
он не будет массивом, поэтому для обеспечения того, чтобы вы могли использовать[array] $collection = ...
В качестве альтернативы, более простым решением является использование того факта, что фильтрация на основе подстановочных знаков с помощью -Filter
параметра выполняется быстро, так что даже Get-ChildItem
повторный вызов, скорее всего, не будет проблемой:
$dir = 'C:usersabrahOneDriveDesktop'
[array] $Desk = (Get-ChildItem -LiteralPath $dir -Filter deskt*).FullName
[array] $VA = (Get-ChildItem -LiteralPath $dir -Filter *v*).FullName
[pscustomobject] @{
DesktopLocation = $Desk
DCount = $Desk.Count
VLocation = $VA
VCount = $VA.Count
}
Комментарии:
1.
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
Это ошибка, которую я получаю при попытке запустить первый блок кода, второй работает нормально, но я не уверен, почему первый выполняет.2. Честно говоря, я просто хотел поработать,
switch
чтобы увидеть все, что он может сделать. Я знаю, что я мог бы сделать это, как 6 разных способов сделать это, но пытался немного поэкспериментировать. Действительно пытался применить этот новый метод к запросу AD для пользователей с определенными словами в их имени.3. Понял, @AbrahamZinala. Что касается сообщения об ошибке: это означает, что вы использовали массив , а не
[System.Collections.Generic.List[string]]
экземпляр, как показано в первом фрагменте. Массивы представляют собой коллекции фиксированного размера, но поскольку они также реализуютSystem.Collections.IList
интерфейс, у них есть.Add()
метод, который всегда завершается ошибкой.4. Есть ли что-нибудь, что вы рекомендуете мне изучить, чтобы изучить такие вещи? Книги, видео, форумы? Кажется, вы это хорошо понимаете
5. @zett42: Я никогда особо не изучал реализацию, но я думаю , что an
ArrayList
, который эффективно растет, используется за кулисами, а затем преобразуется в массив. Несколько связанное обсуждение на GitHub . Если вы хотите поэкспериментировать с относительной производительностью:$a = 1..1e6; Time-Command { $l = [System.Collections.Generic.List[object]] @(); foreach ($e in $a) { $l.Add($e) } }, { $l = foreach ($e in $a) { $e } }
Ответ №2:
Вам не нужен switch
foreach
цикл или, чтобы подсчитать, сколько файлов соответствует каждому имеющемуся у вас шаблону:
# Fetch files
$gc = Get-ChildItem -Path 'C:usersabrahOneDriveDesktop'
# Count those starting with "Deskt"
$desktopFiles = $gc |Where-Object Name -like "Deskt*"
# Count those matching `*v*`
$vFiles = $gc |Where-Object Name -like "*v*"
# Output details
[PSCustomObject]@{
DesktopLocations = @($desktopFiles.FullName)
DesktopCount = $desktopFiles.Count
VLocations = @($vFiles.FullName)
VCount = $vFiles.Count
}
Комментарии:
1. спасибо за комментарий! Просто хотел поработать,
switch
чтобы посмотреть, что все это может сделать.
Ответ №3:
Другое решение:
$Grouped=Get-ChildItem -Path 'C:usersabrahOneDriveDesktop' -file | %{
if ($_.Name -like "Deskt*")
{
Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "DESK_FILE"
}
elseif ($_.Name -like "*v*")
{
Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "V_FILE"
}
else
{
Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "OTHER_FILE"
}
$_
} | Group TypeFile -AsHashTable
#result
$Grouped
#if you want files for a group
$Grouped["V_FILE"]
#if you want really your result
[PSCustomObject]@{
DesktopLocations = $Grouped["DESK_FILE"].fullName
DesktopCount = $Grouped["DESK_FILE"].Count
VLocations = $Grouped["V_FILE"].fullName
VCount = $Grouped["V_FILE"].Count
}