Welcome to Powergui.org - an open source community for Windows Powershell

PowerGUI.org PowerGUI.org and blogs

Forums » PowerGUI User Discussions

Thread: Help with Write-Progress

This question is answered. Helpful answers available: 2. Answered answers available: 1.


Permlink Replies: 5 - Pages: 1 - Last Post: Dec 9, 2009 7:17 AM by: jwpj
jwpj

Posts: 42
Registered: 9/29/09
Help with Write-Progress
Posted: Nov 24, 2009 8:01 AM
 
  Click to reply to this thread Reply

First, I'd like to thank Antize for all his help in getting this code put together.

So I have a script here that searches through a filesystem based on a path and name that the user will input. Basically, if an employee is terminated, I want to be able to search the filesystem and find any file that the person is the owner of.

I am in the process of testing it, and I realized that it is going to take a while to search the whole filesystem, so i decided on putting a progress bar to let users know that it is in fact working. Here is my code:

[System.IO.FileInfo] $Path = read-host -prompt "Please enter the path you wish to search."
[System.IO.FileInfo] $tmpFile =[System.IO.Path]::GetTempFileName()
[string] $User = read-host -prompt "Please enter the unique name of the user you wish to search"


#attempt for a status bar
for ($a=100; $a -gt 1; $a--) {
 Write-Progress -Activity "Working..." `
   -SecondsRemaining $a -CurrentOperation
   "$a% complete" `
   -Status "Please wait."
  Start-Sleep 1
}

#Search for file based on path and username provided. Errors should not display.
Get-ChildItem -Path $Path.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object {-not $_.PsIsContainer} | foreach {
 
    $currentFile = $_
     
    trap
    {
        continue
    }

    $Error.Clear()
 
    $Acl = Get-Acl -Path $currentFile.Fullname
   
   
 
    if ($Error[0] -eq $null)
    {
        if ($Acl.Owner -eq $User)
        {
            $currentFile.Fullname | Out-File $tmpFile.FullName -append
            [int] $hits += 1
        }
    }
   
}

if ($hits -gt 0)
{
    notepad.exe $tmpFile.FullName
}
else
{
    Write-Warning ("No files were found with the owner: " + $User)
}


When I try to run it, I'm getting the following error:

You must provide a value expression on the right-hand side of the '-' operator.
At E:\scripts\John_Dev\Chris\FSsearch.ps1:22 char:5
+    - <<<< Status "Please wait."

I've searched for the error online, but no clear explanation. Anyone have any ideas?

Thanks again all.
Message was edited by: jwpj Message was edited by: jwpj


Oleg Shevnin

Posts: 359
Registered: 7/15/08
Re: Help with Write-Progress
Posted: Nov 24, 2009 9:22 AM   in response to: jwpj
 
  Click to reply to this thread Reply

It looks like you've missed ` (backtick) symbol at the end of this line:

-SecondsRemaining $a -CurrentOperation




antize


Posts: 122
Registered: 2/21/09
Re: Help with Write-Progress
Posted: Nov 25, 2009 9:26 AM   in response to: jwpj
 
  Click to reply to this thread Reply

Yep as Oleg said make sure you get the back tick in there for your line continuation. This will get the code to at least compile however I see a couple issues i'd like to point out.

The way you have write-progress will basically wait 100 seconds before the script actually starts doing anything and will not show progress while it's actually executing which is not what I think you are looking for. It also looks like you want to show a percent complete and estimated time remaining, while cool it is much more difficult to calculate this information. You would have to count all the files in the target folder and keep track of how many files you have processed already to provide an accurate percentage complete metric. Calculating the amount of time left is even more complicated. If you would just like to show the user that script is processing may I suggest the following:

#Search for file based on path and username provided. Errors should not display.
Get-ChildItem -Path $Path.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object {-not $_.PsIsContainer} | foreach {
 
    $currentFile = $_

    Write-Progress -Activity "Searching for file owners..." -CurrentOperation $currentFile.FullName -Status "Current File:"
     
    trap
    {
        continue
    }

    $Error.Clear()
 
    $Acl = Get-Acl -Path $currentFile.Fullname
   
   
 
    if ($Error[0] -eq $null)
    {
        if ($Acl.Owner -eq $User)
        {
            $currentFile.Fullname | Out-File $tmpFile.FullName -append
            [int] $hits += 1
        }
    }
   
}

if ($hits -gt 0)
{
    notepad.exe $tmpFile.FullName
}
else
{
    Write-Warning ("No files were found with the owner: " + $User)
}



The code above won't show a percentage complete or an estimated time remaining, but it will show the user that the script is processing properly.

BTW here is a cool little script I wrote a while ago before the sysinternals suite was available. It would scrub the sysinternals site for tools and download them. It has a write-progress implementation that shows percentage complete -



# Constants
[System.Uri]$baseUrl = 'http://live.sysinternals.com'
[String]$regex = '/([A-z0-9]*\.(.){0,4}(exe|chm|sys|hlp))'

# Setup output folder
[Object]$app = new-object -ComObject Shell.Application
[Object]$folder = $app.BrowseForFolder(0, 'Select Folder to Store Sysinternals Tools', 1)
[string]$savePath = $folder.Self.Path

if ([System.IO.Directory]::Exists($savePath)) {
    [System.IO.DirectoryInfo]$outputFolder = Get-Item($savePath)
   
    # Use the default proxy configuration
    $client = New-Object System.Net.WebClient
    $client.Proxy = [System.Net.WebRequest]::DefaultWebProxy
    $client.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
   
    # Scrub the page for paths
    [string]$code = $client.DownloadString($baseUrl)
    [System.Text.RegularExpressions.MatchCollection]$matches = [regex]::Matches($code, $regex, "IgnoreCase")
   
    for ($i=0; $i -lt $matches.Count -1; $i++) {
            # Setup paths
            [string]$fileName = $matches[$i].Groups[1].Value
            [string]$path = Join-Path -Path $outputFolder.FullName -ChildPath $fileName
            [System.Uri]$url = $baseUrl.AbsoluteUri + $fileName
       
            # Show a progress bar with download status
            [int]$percentComplete = (($i + 1) / $matches.Count) * 100
            [string]$activity = 'Downloading ' + $url.AbsoluteUri
            [string]$status = "Saving " + $path
            Write-Progress -Activity $activity -Status $status -PercentComplete $percentComplete
       
            # Download
            trap [System.Net.WebException] {write-host ("Error: " + $_ + " Failed to download " + $url + ".") -Foregroundcolor Red; Continue}
            $client.DownloadFile($url, $path)
        }
    explorer.exe $savePath
} else {
    Write-Host The selected path ($savePath) was not valid.
}


Message was edited by: antize


jwpj

Posts: 42
Registered: 9/29/09
Re: Help with Write-Progress
Posted: Nov 30, 2009 6:36 AM   in response to: antize
 
  Click to reply to this thread Reply

Thanks guys. Antize, that progress status looks great. The script seems to be doing exactly what I need it to, which is awesome.

I am trying to save the temp file to a specific folder on my desktop using this code:

if ($hits -gt 0)
{
    #notepad.exe $tmpFile.FullName   
    $tmpFile.FullName | out-file 'C:\Documents and Settings\jwpj\Desktop\User_Search_Logs\User_Search-$date.txt'
}
else
{
    Write-Warning ("No files were found with the owner: " + $User)
}

in bold is what i have tried to change in order to accomplish this. Basically I want to put the date on the end of the file, so that every time the script is run, the user will be able to distinguish his run from previous ones. Any reason you can see why this wouldn't work? I'm not seeing the file in that folder.

I set the date variable earlier up in the code $date = get-date

thx




antize


Posts: 122
Registered: 2/21/09
Re: Help with Write-Progress
Posted: Nov 30, 2009 7:12 PM   in response to: jwpj
 
  Click to reply to this thread Reply

Sure couple issues there -

1. $date is actually not a built in variable. To see what you have "built-in", start a new shell and use the get-variable cmdlet. To get the date, you'll need to use the Get-Date cmdlet. However, you'll need to format the cmdlet output a little before you can use it in a file name because the default format from get-date will have invalid filename characters. This will format it for you:

"{0:hh-mmtt_MM-dd-yyyy}" -f (get-date)

  will look like:

10-06PM_11-30-2009

For more on formatting to make it the way you want it, check this out -
http://tfl09.blogspot.com/2007/11/formatting-with-powershell.html (search for "TIME AND DATE")

2. You'll need to use double quotes around a string that contains variables. If you use single quotes, instead of the variable name being replaced with the variable value, you'll get the string $date literally.

3. Make sure to keep the -append parameter for the out-file cmdlet.

Here is some code updated with these tips:


[System.IO.FileInfo] $Path = read-host -prompt "Please enter the path you wish to search."

[string] $User = read-host -prompt "Please enter the unique name of the user you wish to search"

[String] $currentDateTime = "{0:hh-mmtt_MM-dd-yyyy}" -f (get-date)
[System.IO.FileInfo] $tmpFile = "C:\Documents and Settings\jwpj\Desktop\User_Search_Logs\User_Search-$currentDateTime.txt"

#Search for file based on path and username provided. Errors should not display.
Get-ChildItem -Path $Path.FullName -Recurse -ErrorAction SilentlyContinue | Where-Object {-not $_.PsIsContainer} | foreach {
 
    $currentFile = $_

    Write-Progress -Activity "Searching for file owners..." -CurrentOperation $currentFile.FullName -Status "Current File:"
    
    trap
    {
        continue
    }

    $Error.Clear()
 
    $Acl = Get-Acl -Path $currentFile.Fullname
  
  
 
    if ($Error[0] -eq $null)
    {
        if ($Acl.Owner -eq $User)
        {
            $currentFile.Fullname | Out-File $tmpFile.FullName -append
            [int] $hits += 1
        }
    }
  
}

if ($hits -gt 0)
{
    notepad.exe $tmpFile.FullName
}
else
{
    Write-Warning ("No files were found with the owner: " + $User)
}






jwpj

Posts: 42
Registered: 9/29/09
Re: Help with Write-Progress
Posted: Dec 9, 2009 7:17 AM   in response to: jwpj
 
  Click to reply to this thread Reply

Thanks to antize for all of his help finalizing this script. It is working fantastic.


Legend
MVP: 2501 + pts
Guru: 2001 - 2500 pts
Expert: 751 - 2000 pts
Enthusiast: 31 - 750 pts
Novice: 0 - 30 pts
Moderators
Helpful answer (5 pts)
Answered (10 pts)

Point your RSS reader here for a feed of the latest messages in all forums