none
Поссчитать объем домашней папки с условием RRS feed

  • Вопрос

  • Доброго всем дня.
    Подскажи пожалуйста, как правильно посчитать объем домашней папки, и вывести на экран только те папки чей суммарный объем превышает 1G
    ------------
    имеем D:\homes  где лежат папки user1 user2 user3 и т.д
    ------------
    вот что у меня получилось пока
    1PS C:\> Get-ChildItem -Path D:\homes |ForEach-Object { Get-ChildItem $_ -Recurse | Measure-Object -Property Length -Sum|Format-list Count,Sum} 
    2 
    3Count : 4 
    4Sum   : 638464 
    5 
    6Count : 210 
    7Sum   : 53135979 
    8 
    9PS C:\>
    При таком варианте не могу допереть куда вставить if на общий размер папки. и выводится он не красиво, там по 3 энтера получается между блоками текста.
    -------------
    второй вариант получился такой
    1PS C:\> $summ = Get-ChildItem user1 -Recurse | Measure-Object -Property Length -Sum ; $summ.sum=$summ.sum/1Mb ;if ( $summ.sum -gt 1) {$summ.sum=[math]::round($summ.sum,2);$summ|format-list count,sum} 
    2 
    3 
    4Count : 210 
    5Sum   : 50,67 
    6 
    7 
    8 
    9PS C:\> 

    Тут уже как бы лучше, получилось условие вставить, но не пойму как сделать для всех папок.
    Подскажите пожалуйста, и хотелось бы чтоб вывод был таким
    Name: user1
    Count : 210
    Sum   : 50,67
    Заранее благодарен

    16 марта 2009 г. 15:22

Ответы

  • dir c:\users |   
    where {$_.PSIsContainer} |  
    foreach {  
        $u=$_ 
        $u | dir -Recurse |   
        Measure-Object -Sum length |   
        select @{name="Name"; expression={$u.name}},   
            count,   
            @{n="Summ"; e={"{0:n2}" -f($_.sum/1mb)}}  

    Вывод будет в таблице. Если всё же хотите списком, то в конце | format-list
    AKA Xaegr, MCSE: Security, Messaging; MCITP: Server\Enterprise Administrator; Блог: http://xaegr.wordpress.com
    • Предложено в качестве ответа Vasily GusevModerator 17 марта 2009 г. 5:19
    • Помечено в качестве ответа Andrey Zakharchenko 17 марта 2009 г. 7:12
    16 марта 2009 г. 18:49
    Модератор
  • Спасибо большое!
    Дали от чего оттолкнуться :) понял что в данном случае будет уместен where-object чем делать проверку в if
    так что скрипт принял такой вид на данный момент
    1Get-ChildItem H:\Homes |    
    2Where-Object {$_.PSIsContainer} |   
    3ForEach-Object {   
    4    $u=$_  
    5    $u | Get-ChildItem -Recurse |     
    6    Measure-Object  Length -Sum | Where-Object {$_.sum -gt 1Gb} |  
    7    select @{name="Name"; expression={$u.name}},    
    8        count,    
    9        @{n="Summ"; e={"{0:n2}" -f ($_.sum/1mb)}}   
    10} | ConvertTo-Html -Head " <link rel='stylesheet' href='C:\styles.css' type='text/css' />" |Out-file  user.html 
    Только изредка выскакивает вот такое при запуске скрипта
    Measure-Object : Property "Length" cannot be found in any object(s) input. 
    At C:\user-dir-size.ps1:6 char:19 
    +     Measure-Object  <<<<  Length -Sum | Where {$_.sum -gt 1Gb} | 
    Но вроде считает верно, не понятно как у файла не может быть свойства Length
    • Помечено в качестве ответа Andrey Zakharchenko 17 марта 2009 г. 7:12
    17 марта 2009 г. 2:51
  • Посмотрите хорошее описание работы с параметрами http://bsonposh.com/archives/435
    Расширения PowerShell V2 http://tfl09.blogspot.com/2009/01/parameter-attributes-in-powershell-v2.html

    Сазонов Илья http://www.itcommunity.ru/blogs/sie/
    • Помечено в качестве ответа Andrey Zakharchenko 17 марта 2009 г. 15:28
    17 марта 2009 г. 11:19
    Модератор

Все ответы

  • dir c:\users |   
    where {$_.PSIsContainer} |  
    foreach {  
        $u=$_ 
        $u | dir -Recurse |   
        Measure-Object -Sum length |   
        select @{name="Name"; expression={$u.name}},   
            count,   
            @{n="Summ"; e={"{0:n2}" -f($_.sum/1mb)}}  

    Вывод будет в таблице. Если всё же хотите списком, то в конце | format-list
    AKA Xaegr, MCSE: Security, Messaging; MCITP: Server\Enterprise Administrator; Блог: http://xaegr.wordpress.com
    • Предложено в качестве ответа Vasily GusevModerator 17 марта 2009 г. 5:19
    • Помечено в качестве ответа Andrey Zakharchenko 17 марта 2009 г. 7:12
    16 марта 2009 г. 18:49
    Модератор
  • Спасибо большое!
    Дали от чего оттолкнуться :) понял что в данном случае будет уместен where-object чем делать проверку в if
    так что скрипт принял такой вид на данный момент
    1Get-ChildItem H:\Homes |    
    2Where-Object {$_.PSIsContainer} |   
    3ForEach-Object {   
    4    $u=$_  
    5    $u | Get-ChildItem -Recurse |     
    6    Measure-Object  Length -Sum | Where-Object {$_.sum -gt 1Gb} |  
    7    select @{name="Name"; expression={$u.name}},    
    8        count,    
    9        @{n="Summ"; e={"{0:n2}" -f ($_.sum/1mb)}}   
    10} | ConvertTo-Html -Head " <link rel='stylesheet' href='C:\styles.css' type='text/css' />" |Out-file  user.html 
    Только изредка выскакивает вот такое при запуске скрипта
    Measure-Object : Property "Length" cannot be found in any object(s) input. 
    At C:\user-dir-size.ps1:6 char:19 
    +     Measure-Object  <<<<  Length -Sum | Where {$_.sum -gt 1Gb} | 
    Но вроде считает верно, не понятно как у файла не может быть свойства Length
    • Помечено в качестве ответа Andrey Zakharchenko 17 марта 2009 г. 7:12
    17 марта 2009 г. 2:51
  • Наверное это он на папки ругается, хотя странно... Попробуйте в пятую строку тоже добавить where {$_.psiscontainer} |


    AKA Xaegr, MCSE: Security, Messaging; MCITP: Server\Enterprise Administrator; Блог: http://xaegr.wordpress.com
    17 марта 2009 г. 5:18
    Модератор
  • Тык в том-то и дело, что не на папки, так как в корне папок ~1500, ну и вложенные, а от силы ругательств 20-25
    --------------
    добавил и оно повалило :) без вашего добавления их было меньше
    17 марта 2009 г. 5:26
  • Тогда наверное какие то проблемы с доступом. То есть получить имя можете, а размер нет. Что за файлы?

    Давайте тогда в 5ую вместо where {$_.psiscontainer} Добавьте foreach {write-host ($_.fullname)} |
    чтобы увидеть проблемные файлы



    AKA Xaegr, MCSE: Security, Messaging; MCITP: Server\Enterprise Administrator; Блог: http://xaegr.wordpress.com
    17 марта 2009 г. 5:40
    Модератор
  • Я то же думаю что проблема с доступом, скрипт по смене владельца и пирмишенов это следующий что я пишу :)
    -----------
    я боюсь что наверно лучше в файл, так как там будет очень много. ща запущу

    17 марта 2009 г. 5:49
  • Да, похоже на папки ругается, вроде получилось локализовать ошибку, как разберусь дам ответ.
    17 марта 2009 г. 7:12
  • Я понимаю что не в тему, но не могли бы вы подсказать как сделать запуск скрипта с параметром. то есть например
    ./user-dir-size.ps1 -full
    ./user-dir-size.ps1 -low
    а точ при простом запуске
    ./user-dir-size.ps1 выводилась справка о том что нужно использовать один из параметром.
    ----------
    каюсь :) пока в книге найти просто не могу, как такое реализовать.
    17 марта 2009 г. 7:23
  • Посмотрите хорошее описание работы с параметрами http://bsonposh.com/archives/435
    Расширения PowerShell V2 http://tfl09.blogspot.com/2009/01/parameter-attributes-in-powershell-v2.html

    Сазонов Илья http://www.itcommunity.ru/blogs/sie/
    • Помечено в качестве ответа Andrey Zakharchenko 17 марта 2009 г. 15:28
    17 марта 2009 г. 11:19
    Модератор
  • Спасибо, получается как в sh, можно через $args массив :)
    ---------------------
    интересно, где вы находите эти блоги :) хотя возможно через какое-то время и у меня в закладках будет по статейки на все случаи жизни, я же только начал его изучать и пользоваться и пока только положительные эмоции
    17 марта 2009 г. 15:28
  • Блоги просто гуглятся :) Достаточно добавить ключевое слово Powershell :)

    Использовать $args - некрасивый и ненадёжный метод, лучше его использовать только когда нет другого выхода.

    param ([switch]$full, [switch]$low)

    if ($full) {write-host "указан ключ -full"}
    elseif ($low) {write-host "указан ключ -low"}
    else {write-host "ключи не указаны"}

    Еще рекомендую подглядывать в примеры скриптов у меня в блоге (в подписи ;)) или например на poshcode.org
    AKA Xaegr, MCSE: Security, Messaging; MCITP: Server\Enterprise Administrator; Блог: http://xaegr.wordpress.com
    17 марта 2009 г. 17:57
    Модератор
  • я так понял что param() можно использовать только в powershell v2, у меня пока стоит первой версии :)
    ваш блог у меня почти первым появился в закладках :)
    18 марта 2009 г. 6:26
  • param () доступен и в первой версии PowerShell. Точнее в любой.
    [тут могла быть ваша реклама] http://www.sysadmins.lv
    18 марта 2009 г. 6:42
  • Zakharchenko Andrey написал:

    Я понимаю что не в тему, но не могли бы вы подсказать как сделать запуск скрипта с параметром. то есть например
    ./user-dir-size.ps1 -full
    ./user-dir-size.ps1 -low
    а точ при простом запуске
    ./user-dir-size.ps1 выводилась справка о том что нужно использовать один из параметром.
    ----------
    каюсь :) пока в книге найти просто не могу, как такое реализовать.


    как вариант, в начале скрипта делаете примерно так:
    param ([switch]$full, [switch]$low)
    # проверяем, если не указано ни одного ключа или указано 2 ключа, то выводится справка и остановка скрипта/функции
    if ((!$full -and!$low) -or ($full -and $low)) {
        write-warning "тут должна быть справка"
        return
    }
    <остальной код>.

    В принципе, сразу должна идти проверка:
    if ($full) {<тут код, который выполняется при указанном ключе -full>}
    if ($low) {<тут код, который выполняется при указанном -low>}
    [тут могла быть ваша реклама] http://www.sysadmins.lv
    18 марта 2009 г. 7:05
  • Vadims Podans написал:

    как вариант, в начале скрипта делаете примерно так:
    param ([switch]$full, [switch]$low)
    # проверяем, если не указано ни одного ключа или указано 2 ключа, то выводится справка и остановка скрипта/функции
    if ((!$full -and!$low) -or ($full -and $low)) {
        write-warning "тут должна быть справка"
        return
    }
    <остальной код>.

    В принципе, сразу должна идти проверка:
    if ($full) {<тут код, который выполняется при указанном ключе -full>}
    if ($low) {<тут код, который выполняется при указанном -low>}
    [тут могла быть ваша реклама] http://www.sysadmins.lv


    PS J:\> param ([switch]$full, [switch]$low) 
    Условие "param" не распознано как командлет, функция, выполняемая программа или файл сценария. Проверьте условие и повторите попытку. 
    В строка:1 знак:6 
    + param  <<<< ([switch]$full, [switch]$low) 
    PS J:\
    Вот как консоль у меня ругается, если в консоле
    -----------------------
    понял! оно только в скрипте работает! блин :) я прост опривык проверять сначала в консоле команду, из этого и сделал вывод
    18 марта 2009 г. 8:36
  •  чтобы проверить в консоли, сделайте функцию:
    function test {param (bla-bla-bla) ...}

    и потом вызовом функции проверять действие param

    или вот так:

    function Test {
    param ([switch]$full, [switch]$low)
    if ((!$full -and!$low) -or ($full -and $low)) {write-warning "так низя";return}
    if ($full) {Write-Host "задан ключ -full"}
    if ($low) {Write-Host "задан ключ -low"}
    }

    # проверка без ключей:
    test
    # проверка с обоими ключами:
    test -full -low
    test -low -full
    # последовательная проверка с каждым ключом
    test -full
    test -low


    [тут могла быть ваша реклама] http://www.sysadmins.lv

    18 марта 2009 г. 8:39
  • Да, до функции я уже додумал :) спасибо.
    Ну, понимаю что это уже через чур, но все же спрошу.
    Вот у меня есть пример
    To process Named parameters you use the Param() statement included in Powershell 
     
        Example: PassByName -list filename.txt -domain corp.lab 
     
    function PassByName{ 
        Param($FileName,$DomainName) 
        "FileName: {0}" -f $FileName 
        "Domain: {0}" -f $DomainName 
    Пробую его.
    PS J:\> PassByName -list filename.txt -domain corp.lab 
    FileName: 
    Domain: corp.lab 
     
    Почему у меня первый параметр не прочитался? на вид вроде все правильно получается. При чем если убрать параметры -list и -domain, то читаются оба
    ------------
    получается там ошибка, так как если запустить так
    PassByName -file filename.txt -domain corp.lab
    То читаются оба параметра.
    PS J:\> PassByName -list filename.txt -dom corp.lab 
    FileName: 
    Domain: corp.lab 
    PS J:\> 
    я так понимаю что в общем эти параметры -list и -domain не нужны. По идеи я же его не правильно задал -dom, и он не должен был прочитать название файла и прерваться с ошибкой.
    При чем если задать скажем -domainsdasdasda то параметр опять читается.
     
    18 марта 2009 г. 9:42
  • в данном случае не нужны, поскольку если им соответствие не найдено, то они рассатавляются по порядку. Вам же они нужны и должны совпадать с именами (или началом имён до уникальности) переменных, которые находятся в param ().
    [тут могла быть ваша реклама] http://www.sysadmins.lv
    18 марта 2009 г. 15:36
  • Доброго всем дня.
    Сейчас мой скрипт имеет такой вид:
    1param ($path,$size,$diff,$min) 
    2#$diff = "no"; 
    3$text = "`n
    4        `t Надо использовать следующий синтаксис скрипта:
    5        `t -path - путь до домашней папки
    6        `t -size - размер папки, поддерживается сокращения: Gb,Mb,Kb
    7        `t -diff - вычислить кто почти достиг придела в диапазоне: yes|no. Default no
    8        `t -min  - минимальный размер, используется в паре с -size
    9        `t---------------------------------------------------------------------------
    10        `t Пример: 
    11        `t ./1.ps1 -path ""T:\!"" -size 100Mb
    12        `t ./1.ps1 -path ""T:\!"" -size 100Mb -diff yes -min 1Mb" 
    13 
    14if ((!$diff) -or ($diff -eq "no")) { 
    15    if (!$path -or !$size ) { 
    16    write-warning $text ; 
    17    return 
    18    } 
    19
    20else { 
    21    if ((!$path -or !$size -or !$min) -or ($diff -ne "yes")) { 
    22    write-warning $text ; 
    23    return 
    24    } 
    25
    26 
    27Get-ChildItem -LiteralPath $path |   
    28Where-Object {$_.PSIsContainer} |   
    29ForEach-Object {   
    30    $u=$_ 
    31    $u | Get-ChildItem -Recurse | 
    32    Measure-Object  Length -Sum | 
    33    Where-Object {($_.sum -gt $min) -and ($_.sum -lt $size)} | 
    34#    Where-Object {($_.sum -gt $size)} | 
    35    Select @{name="Name"; expression={$u.name}},   
    36        count,   
    37        @{n="Summ"; e={"{0:n2}Mb" -f ($_.sum/1Mb)}}   
    38}  


    Я хочу реализовать, что если задаешь параметр -diff yes, но скрипт вычисляет кто почти приблизился к нужному значению в диапазоне, от скажем 900Mb до 1Gb. Я понимаю что можно просто комментировать/раскоментировать нужную страку и будет счастье. НО хочется сделать правильно на мой взгляд.
    Я понял что Where-Object {($_.sum -gt $min) -and ($_.sum -lt $size)} и Where-Object {($_.sum -gt $size)} нужно сделать функциями и в нужном if их задавать. Проблема у меня в том, что не могу этой функции передать $_
    Пробую сделать function test ($size) {Where-Object {($_.sum -gt $size)}}
    заменяю следующию строку на Where-Object {($_.sum -gt $size)} на test $size, запускаю скрипт, но условие не выполняется, у меня ощущение что он не получает данные из $_
    Можите подсказать чего я не так делаю?
    22 марта 2009 г. 6:22
  • Что вы себе жизнь усложняете? :-) Вы в условие if вложите всю конструкцию начиная с Get-ChildItem - только в одной ветке у вас будет Where-Object {($_.sum -gt $min) -and ($_.sum -lt $size)} а в другой Where-Object {($_.sum -gt $size)}
    Сазонов Илья http://www.itcommunity.ru/blogs/sie/
    23 марта 2009 г. 14:38
    Модератор
  • А функцию вы не правильно пишите: функции, которые могут работать в конвейере, имеют специальную форму.
    http://huddledmasses.org/writing-better-script-functions-for-the-powershell-pipeline/


    Сазонов Илья http://www.itcommunity.ru/blogs/sie/
    23 марта 2009 г. 14:55
    Модератор
  • sie написал:

    Что вы себе жизнь усложняете? :-) Вы в условие if вложите всю конструкцию начиная с Get-ChildItem - только в одной ветке у вас будет Where-Object {($_.sum -gt $min) -and ($_.sum -lt $size)} а в другой Where-Object {($_.sum -gt $size)}


    Сазонов Илья http://www.itcomunity.ru/blogs/sie/

    это я понимаю, что можно так. но хочется научится так сказать.
    sie написал:

    А функцию вы не правильно пишите: функции, которые могут работать в конвейере, имеют специальную форму.
    http://huddledmasses.org/writing-better-script-functions-for-the-powershell-pipeline/


    Сазонов Илья http://www.itcommunity.ru/blogs/sie/

    за это спасибо, вроде то!
    24 марта 2009 г. 5:49
  • Zakharchenko Andrey написал:

    sie написал:

    Что вы себе жизнь усложняете? :-) Вы в условие if вложите всю конструкцию начиная с Get-ChildItem - только в одной ветке у вас будет Where-Object {($_.sum -gt $min) -and ($_.sum -lt $size)} а в другой Where-Object {($_.sum -gt $size)}


    Сазонов Илья http://www.itcomunity.ru/blogs/sie/

    это я понимаю, что можно так. но хочется научится так сказать.



    В скрипт блоке Where-Object можно использовать оператор:

     switch ($diff -eq "yes"
    {
       True  {}
       False {}

    }

    Сазонов Илья http://www.itcommunity.ru/blogs/sie/
    24 марта 2009 г. 8:39
    Модератор