Ad Space here

Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Share
Options
Go to last post Go to first unread
Dustin Higgins  
#1 Posted : Thursday, December 26, 2019 12:33:08 AM(UTC)
Dustin Higgins

Rank: Advanced Member

Groups: Registered
Joined: 7/1/2018(UTC)
Posts: 64
_United States

Thanks: 1 times
Was thanked: 6 time(s) in 6 post(s)

PowerShell and Getting Basic FileInfo with a Timeout


A few weeks ago I posted about starting a .NET Process with a Timeout through PowerShell that will redirect StdOut and StdErr. Today, I am going to build on that by demonstrating a practical example that does scale.  I know I'm going to take some dings for using the older "dir" command instead of "Get-Item".  I am totally prepared for that.  At the end of the day, I'm working with PowerShell object data to fix issues instead of waiting for scripts to complete.  When dealing with lots of endpoints, every second counts.  The ability to shave 10 seconds off of a 20 second RPC timeout makes a big difference when dealing with 20K endpoints.  Thread this out and it becomes incredibly fast.

This solution is a little different by mixing the old and the new.  It is what I call a "hybrid" solution which is really starting to become our MO more than ever.  I've said it many times, the true greatness of PowerShell is the ability to get to the answer many different ways.  Below is mine. ​​​​​​​

​​​​​​​

Code:
function Get-DirFileInfo
{
    <#
    .SYNOPSIS
    Function to get file info from the "dir" command.
    .DESCRIPTION
    Function to get file info from the "dir" command.  This function calls
    Start-ProcessWaitTimeout so it will only wait as long as the timeout.
    #>
    param (
        [Parameter(Mandatory=$true)]
        [string]$Computer,
        [Parameter(Mandatory=$true)]
        [string]$FilePath
    )
    # Create the Object
    $Obj = [PSCustomObject]@{
        Computer = $Computer
        Online = $null
        FilePath = $FilePath
        DirPath = $null
        FileName = $null
        Exists = $null
        Size = $null
        LastModifiedDate = $null
        CmdResult = $null
    }
    # Change the Directory path to the UNC path

    $Obj.DirPath = "\\$($Computer)\$($FilePath.Substring(0,$FilePath.LastIndexOf("\")).Replace(":","$"))"     # Set the File Name     $Obj.FileName = $FilePath.Split("\")[-1]     ## CHECK PING STATUS - RETURN IF OFFLINE     $pingStatus = ping -n 1 -4 $computer     if ($?) {         if ($pingStatus -match "unreachable" -or $pingStatus -match "could not find host" -or $pingStatus -match "timed out") {             $Obj.Online = $false             Return $Obj         } else {             $Obj.Online = $true         }     } else {         $Obj.Online = $false         Return $Obj     }     # Setup the Command     $Cmd = "C:\Windows\System32\cmd.exe"     $CmdArgs = @("/c","dir","/-c","""$($Obj.DirPath)\$($Obj.FileName)""")     # Run the Command     $Obj.CmdResult = Start-ProcessWaitTimeout -Computer $Computer -CmdLine $Cmd -CmdLineArgs $CmdArgs -Timeout 10     # Loop throught the StdOut     foreach ($i in $Obj.CmdResult.ProcessStdOut.Split("`n")) {         if ($i -match "(?<Date>\d\d/\d\d/\d\d\d\d)\s+(?<Time>\d\d:\d\d\s\w\w)\s+(?<Size>.*)\s+($($Obj.FileName)).*") {             $Obj.Exists = $true             $Obj.LastModifiedDate = (Get-Date("$($Matches.Date) $($Matches.Time)"))             $Obj.Size = [int]$($Matches.Size)         }     }     # Return the Object     Return $Obj }

# Example

Get-DirFileInfo -Computer "Computer1" -FilePath "C:\Program Files\7-Zip\7z.exe"

Follow Dustin Higgins ​​​​​​​on Twitter and Instagram


Edited by user Monday, December 30, 2019 10:50:13 PM(UTC)  | Reason: Not specified

Sponsor
Ad Space here
postanote  
#2 Posted : Friday, January 03, 2020 7:36:34 PM(UTC)
postanote

Rank: Newbie

Groups: Registered
Joined: 12/14/2019(UTC)
Posts: 1
_United States
Location: California

Well, we know habits are hard to break, especially for us old guys, but still, why dir vs gci, I mean they are both just 3 chars, which I assume you chose dir because of habit or otherwise. ;-} Well, that and gci is still the PowerShelly way .
Sure, sure, we all know, to be proper PowerShell citizens, when using scripts never use aliases or shorthand stuff, but, well, u know. ;-}
Yet, I see what you are doing here and it's a good tip.
Dustin Higgins  
#3 Posted : Friday, January 03, 2020 8:31:53 PM(UTC)
Dustin Higgins

Rank: Advanced Member

Groups: Registered
Joined: 7/1/2018(UTC)
Posts: 64
_United States

Thanks: 1 times
Was thanked: 6 time(s) in 6 post(s)

I really appreciate the feeback and the discussion.  I am using cmd.exe /c dir by design.  That combined with the Start-ProcessWaitTimeout function deals gracefully (timeout and move on) with machines in bad states.  That is the main reason.  I have also tried PS jobs and wmi calls with timeouts.   They don’t seem to handle the bad states gracefully.  An example is that DNS has the incorrect name for a real computer.  That typically results in an RPC timeout that would last ~20 seconds.  It is usually not a big deal when there are not that many machines. Turning the 20 seconds into 5 or 10 seconds makes a big difference when dealing with 1000’s of machines.  Honestly, gci for everything else.  I totally agree.

It is very different, however incredibly fast.  The other thing I really like about it is that you start to see patterns in the data (mainly for housekeeping purposes).


Rss Feed  Atom Feed
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.