обновление значения столбца для экспортированного CSV PowerShell - PullRequest
1 голос
/ 06 апреля 2020

У меня следующий код, который работает правильно. Хотя теперь мне нужно изменить вывод в одном указанном столбце c, чтобы я мог правильно сортировать по этому столбцу.

Вот мой код:

$inputFile  = "C:\Data\expPasswords\expPasswords.csv"
$outputFile = "C:\Data\expPasswords\expPasswordsUp.csv"

$result = Import-Csv $inputFile |
            Select-Object @{ Name = 'Account'; Expression = { $_.Account  } },
                          @{ Name = 'Days until Expiry'; Expression = { $_.'time until password expires' } },
                          @{ Name = 'Email address'; Expression = { $_.'email address'  } }

# output on screen
$result | Sort-Object -Property 'Days until Expiry' | Format-Table -AutoSize

# output to csv
$result | Sort-Object -Property 'Days until Expiry' | Export-Csv -Path $outputFile -NoTypeInformation

Мне нужно отсортировать по столбец «Дни до истечения». Хотя затрудняется, когда вывод, как показано ниже:

0 минут 0 минут 1 день и 19 часов 1 день и 2 часа 1 день и 20 часов 1 день и 23 часа 13 часов 2 дня 20 часов

По сути, я хотел бы сделать следующее: - Если значение меньше 1 дня, сделайте значение: Сегодня - Удалить блоки часов и минут. - Итак, если это 13 часов, сделайте ценность: сегодня - Если значение равно 1 дню и 1 часу и 35 минутам, введите значение: 1 день

Любая помощь будет принята с благодарностью. ; -)

Ответы [ 3 ]

2 голосов
/ 06 апреля 2020

Жаль, что вам стоит потратить время на то, чтобы разобраться в этом довольно глупом выводе sh, но, конечно, это можно сделать. По сути, все, что вам нужно сделать, это выяснить, начинается ли строка с числа, за которым следует слово «день» или «дни», и обрезать все остальные. Если это не так, возвращаемое значение должно быть «Сегодня».

Я думаю, что самый простой способ сделать это - использовать switch -Regex.

Попробуйте

$inputFile  = "C:\Data\expPasswords\expPasswords.csv"
$outputFile = "C:\Data\expPasswords\expPasswordsUp.csv"

$result = Import-Csv $inputFile | ForEach-Object {
    $daysLeft = switch -Regex ($_.'time until password expires') {
        '^(\d+ days?)' { $matches[1] }
        default { 'Today' }
    }
    [PsCustomObject]@{
        'Account'           = $_.Account
        'Days until Expiry' = $daysLeft
        'Email address'     = $_.'email address'
    }
} | Sort-Object -Property 'Days until Expiry'

# output on screen
$result | Format-Table -AutoSize

# output to csv
$result | Export-Csv -Path $outputFile -NoTypeInformation

Подробности регулярного выражения:

^           Assert position at the beginning of the string
\d          Match a single character that is a “digit” (any decimal number in any Unicode script)
   +        Between one and unlimited times, as many times as possible, giving back as needed (greedy)
\ day       Match the character string “ day” literally (case sensitive)
s           Match the character “s” literally (case sensitive)
   ?        Between zero and one times, as many times as possible, giving back as needed (greedy)

Просматривая ваш комментарий, я бы предложил добавить для сортировки настоящий объект DateTime.

Примерно так:

$today = (Get-Date).Date

$result = Import-Csv 'D:\test.csv' | ForEach-Object {
    $expiryString = $_.'time until password expires'
    $expiryDate   = $today
    if ($expiryString -match '(\d+)\s*day')    { $expiryDate = $expiryDate.AddDays([int]$matches[1]) }
    if ($expiryString -match '(\d+)\s*hour')   { $expiryDate = $expiryDate.AddHours([int]$matches[1]) }
    if ($expiryString -match '(\d+)\s*minute') { $expiryDate = $expiryDate.AddMinutes([int]$matches[1]) }
    if ($expiryString -match '(\d+)\s*second') { $expiryDate = $expiryDate.AddSeconds([int]$matches[1]) }

    $daysLeft = if ($expiryDate.Date -eq $today) { 'Today' } else { ($expiryDate - $today).Days}

    [PsCustomObject]@{
        'Account'           = $_.Account
        'Email address'     = $_.'email address'
        'Days until Expiry' = $daysLeft
        'Expiration Date'   = $expiryDate
    }
} | Sort-Object -Property 'Expiration Date'

# output on screen
$result

Вывод:

Account Email address         Days until Expiry Expiration Date  
------- -------------         ----------------- ---------------  
User1   user1@yourcompany.com Today             6-4-2020 0:00:00 
User6   user6@yourcompany.com Today             6-4-2020 0:03:00 
User8   user8@yourcompany.com Today             6-4-2020 13:00:00
User4   user4@yourcompany.com Today             6-4-2020 20:00:00
User9   user9@yourcompany.com 1                 7-4-2020 2:00:00 
User2   user2@yourcompany.com 1                 7-4-2020 19:00:00
User5   user5@yourcompany.com 1                 7-4-2020 20:00:00
User7   user7@yourcompany.com 1                 7-4-2020 23:00:00
User3   user3@yourcompany.com 2                 8-4-2020 0:00:00 

Если вы не хотите, чтобы это новое свойство 'Дата истечения' в вашем выводе, просто отфильтруйте его с помощью:

$result | Select-Object * -ExcludeProperty 'Expiration Date'
1 голос
/ 06 апреля 2020

Я думаю, что следующее может быть полезным (вам нужно будет отредактировать некоторые из них, конечно):

$Timings = @("0 minutes","0 minutes","1 day and 19 hours","1 day and 2 hours","1 day and 20 hours","1 day and 23 hours","13 hours","2 days","20 hours")

foreach ($Timing in $Timings) {
   $Output = $null
   if ($Timing -like "* minutes") {$Output = 0}
    elseif ($Timing -like "* Day and * hours") {$Output = [int](($Timing).Split(' day')[0])}
    elseif ($Timing -like "* hours") {$Output = 0}
   else {$Output = [int](($Timing).Split(' day')[0]) }

   switch ($Output) {
   0 {$Result = "Today"}
   1 {$Result = "Tomorrow"}
   default {$Result = "Over $Output Days"}
   }

   Write-Output "$timing ==> $Result"
}
0 голосов
/ 06 апреля 2020

Определенные вами ограничения, скорее всего, сделают его более запутанным. Я бы просто преобразовал его в [TimeSpan] структуру, которая упрощает сортировку:

$Result = ConvertFrom-Csv @'
"Account","Days until Expiry",  "Email address"
"Account1","0 minutes",         "Name1@gmail.com"
"Account2","1 day and 19 hours","Name2@gmail.com"
"Account3","2 days",            "Name3@gmail.com"
"Account4","20 hours",          "Name4@gmail.com"
"Account5","1 day and 20 hours","Name5@gmail.com"
"Account6","3 minutes",         "Name6@gmail.com"
"Account7","1 day and 23 hours","Name7@gmail.com"
"Account8","13 hours",          "Name8@gmail.com"
"Account9","1 day and 2 hours", "Name9@gmail.com"
'@


Function ConvertTo-TimeSpan([String]$String) {
    $Days    = If ($String -Match '\d+(?=\s*day)')    {$Matches[0]} Else {0}
    $Hours   = If ($String -Match '\d+(?=\s*hour)')   {$Matches[0]} Else {0}
    $Minutes = If ($String -Match '\d+(?=\s*minute)') {$Matches[0]} Else {0}
    $Seconds = If ($String -Match '\d+(?=\s*second)') {$Matches[0]} Else {0}
    New-TimeSpan -Days $Days -Hours $Hours -Minutes $Minutes -Seconds $Seconds
}

$Result | Sort @{e = {ConvertTo-TimeSpan $_.'Days until Expiry'}}

Результат:

Account  Days until Expiry  Email address
-------  -----------------  -------------
Account1 0 minutes          Name1@gmail.com
Account6 3 minutes          Name6@gmail.com
Account8 13 hours           Name8@gmail.com
Account4 20 hours           Name4@gmail.com
Account9 1 day and 2 hours  Name9@gmail.com
Account2 1 day and 19 hours Name2@gmail.com
Account5 1 day and 20 hours Name5@gmail.com
Account7 1 day and 23 hours Name7@gmail.com
Account3 2 days             Name3@gmail.com
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...