Home > Mobile >  Powershell file property listing
Powershell file property listing

Time:07-12

I'm trying to collect some file properties using PowerShell within Win 2008. To do so, I've created the following script.

# BASIC PARAMETER IF NOT SET
param(
    $REGEX='.*'
    )

# CURRENT DATE FROM 00H
$DATAATUAL = Get-Date -Hour 0 -Minute 0 -Second 0 -Day 1 # DAY 1 FOR TESTING ONLY

# APPLICATION'S FILE PATH
$PATH = "C:\FTP\import\"

# FILE LIST WITH SELECTED FILES FROM REGULAR EXPRESSION
$FILELIST = Get-ChildItem -Path $PATH | Where-Object { ($_.LastWriteTime -ge $DATAATUAL) -and ($_.Name -cmatch "$REGEX") } | Select-Object -ExpandProperty Name

# OUTPUT IN A SORT OF CSV FORMAT
if ($FILELIST -ne $null) {

    Write-Host "name;suffix;fileprocstart;filesize;filewrite"

    ForEach ($FILE in $FILELIST) {
        
        # FILE NAME PREFFIX AND SUFFIX
        $FILENAME = Select-String -InputObject $FILE -CaseSensitive -Pattern "(^\d )_($REGEX)"
        
        # FILE TIMESTAMP CONVERTION TO EPOCH UTC-0
        $FILEPROCSTART = $FILENAME.Matches.Groups[1].value
            $FILEPROCSTART = [datetime]::ParseExact($FILEPROCSTART,"yyyyMMddHHmmss",$null) | Get-Date -UFormat "%s"
            $FILEPROCSTART = $($FILEPROCSTART -as [long])   10800  # TIMEZONE CORRECTION - ADDED 3H TO BECOME UTC-0
                        
        $FILESUFFIX = $FILENAME.Matches.Groups[2].value
        
        # FILE SIZE AND WRITE TIME
        $FILESIZE = Get-ChildItem -Path $PATH -Filter $FILE | Select-Object -ExpandProperty Length
        $FILEWRITE = Get-ChildItem -Path $PATH -Filter $FILE | Select-Object -ExpandProperty LastWriteTime | Get-Date -UFormat "%s"
        
        # OUTPUT
        Write-Host "$FILENAME;$FILESUFFIX;$FILEPROCSTART;$FILESIZE;$FILEWRITE"
    }
}

# NO FILES FOUND
Else {
    Write-Host "Empty"
}

I can start it like so:

script.ps1 -REGEX 'pattern'

It results in a list like this:

name;suffix;fileprocstart;filesize;filewrite
20220709101112_cacs1_v83.txt;cacs1_v83.txt;1657361472;5;1657397022,47321
20220709101112_cacs1_v83.txt.log;cacs1_v83.txt.log;1657361472;5;1657397041,83271
20220709101112_cacs2_v83.txt;cacs2_v83.txt;1657361472;5;1657397039,70775
20220709101112_cacs3_v83.txt.log;cacs3_v83.txt.log;1657361472;5;1657397038,03647
20220709101112_cakauto4.txt;cakauto4.txt;1657361472;5;1657397037,48906
20220709111112_coord_multicanal.txt.log;coord_multicanal.txt.log;1657365072;5;1657398468,95865

All files are generated on a daily basis and have a format similar to this:

20220709101112_cacs1_v83.txt
20220709101112_cacs1_v83.txt.log
20220709101112_cacs2_v83.txt
20220709101112_cacs3_v83.txt.log
20220709101112_cakauto4.txt
20220709101112_coord_multicanal.txt.log

Basically, the script outputs the file name, file suffix (no timestamp), file timestamp (unix format), file size and Last Write time (unix format), all in a sort of CSV format. It is meant to be started by another system to collect those properties.

It kind of works, but I can't help thinking there must be a better way to do that.

Any considerations on how to improve it?

CodePudding user response:

I'm not sure if I got it right but if I understand this right:

Basically, the script outputs the file name, file suffix, file name timestamp, file size and Last Write time, all in a sort of CSV format. It is meant to be started by another system to collect those properties.

This should be all you need to start with:

$ComputerName = 'RemoteW2K8Computer'
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
    Get-ChildItem -Path 'C:\FTP\import' |
        Select-Object -Property BaseName,Extension,Length,LastWriteTime,
            @{Name = 'FileNameTimeStamp'; Expression = {($_.BaseName -split '_')[0]}}
}

CodePudding user response:

Using @Olaf great tips, I've rewritten the script this way.

param($REGEX='.*')
$DATAATUAL = Get-Date -Hour 0 -Minute 0 -Second 0 -Day 1 # DAY 1 FOR TESTING ONLY
$PATH = "C:\FTP\import"
$TZ = [TimeZoneInfo]::FindSystemTimeZoneById("E. South America Standard Time")

$FILELIST = Get-ChildItem -Path $PATH |
    Where-Object { ($_.LastWriteTime -ge $DATAATUAL) -and ($_.Name -cmatch "$REGEX") } |
        Select-Object -Property Name,Length,
            @{Name = 'Suffix'; Expression = { ($_.Name -split '_',2)[1] } },
            @{Name = 'ProcStart'; Expression = {
                $PROCSTART = ($_.Name -split '_')[0]; 
                $PROCSTART = [datetime]::ParseExact($PROCSTART,"yyyyMMddHHmmss",$null);
                [TimeZoneInfo]::ConvertTimeToUtc($PROCSTART, $TZ) | Get-Date -UFormat "%s";
                } },
            @{Name = 'FileWrite' ; Expression = {
                $WRITETIME = $_.LastWriteTime;
                [TimeZoneInfo]::ConvertTimeToUtc($WRITETIME) | Get-Date -UFormat "%s";
                } }


if ($FILELIST -ne $null) {
    Write-Host "name;suffix;procstart;filesize;filewrite"
    # $FILELIST | ConvertTo-Csv -Delimiter ';' -NoTypeInformation

    ForEach ($FILE in $FILELIST) {
        $FILENAME = $FILE.Name
        $FILESUFFIX = $FILE.Suffix
        $FILESIZE = $FILE.Length
        $FILEPROCSTART = $FILE.ProcStart
        $FILEWRITE = $FILE.FileWrite
        
        Write-Host "$FILENAME;$FILESUFFIX;$FILESIZE;$FILEPROCSTART;$FILEWRITE"
    }
} 
Else {
    Write-Host "Empty"
}

As said, the output is in a CSV format.

name;suffix;procstart;filesize;filewrite
20220709101112_cacs1_v83.txt;cacs1_v83.txt;5;1657361472;1657397022,47321
20220709101112_cacs1_v83.txt.log;cacs1_v83.txt.log;5;1657361472;1657397041,83271

If I use ConvertTo-Csv (much simpler) instead of ForEach, the output would also be a CSV. However, it places quotation marks that mess up other conversions to JSON elsewhere (maybe I can improve that later).

# $FILELIST | ConvertTo-Csv -Delimiter ';' -NoTypeInformation
"Name";"Length";"Suffix";"ProcStart";"FileWrite"
"20220709101112_cacs1_v83.txt";"5";"cacs1_v83.txt";"1657361472";"1657397022,47321"
"20220709101112_cacs1_v83.txt.log";"5";"cacs1_v83.txt.log";"1657361472";"1657397041,83271"

The other system convert it to this (I can't use ConvertTo-Json in Win2008 :-/):

{
  "\"Name\"": "\"20220709101112_cacs1_v83.txt\"",
  "\"Length\"": "\"5\"",
  "\"Suffix\"": "\"cacs1_v83.txt\"",
  "\"ProcStart\"": "\"1657361472\"",
  "\"FileWrite\"": "\"1657397022,47321\""
}

Therefore, I find that writing the values with ForEach gives me a cleaner output.

Also, for fun, measuring with Measure-Command, I found that the new script is a bit faster. The previous script takes about 24 milliseconds to complete while using a small dataset. Now, the new one takes about 13 milliseconds with the same dataset.

All in all, a small, but good improvement, I guess.

Cheers to @Olaf for pointing to a better script and for his patience. Thank you.

  • Related