Get-SysinternalsTools

I’ve read the following blog post about popular scripts http://blogs.technet.com/b/heyscriptingguy/archive/2012/01/03/top-ten-scripting-wife-blogs-of-2011-show-powershell-skills.aspx and decided last week-end to update my old down_sys.bat file.
I used it to download all files from http://live.sysinternals.com using wget with proxy settings into a folder called live.sysinternals.com. It finally compares files in my current path and produces the following output.
old down_sys.bat file output
Can’t wait any further, so here’s my version of Get-SysinternalsTools.ps1 that uses the same logic:

#Requires -Version 3.0

<#
    
.SYNOPSIS    
    Download sysinternals tools
   
.DESCRIPTION  
    Download all sysinternal tools to .\live.sysinternals.com directory and update previous files located in current path

.PARAMETER Proxy
    Set the proxy address to use to download
     
.NOTES    
    Name: Get-SysinternalsTools
    Author: Emin Atac
    DateCreated: 14/01/2012
     
.LINK    
    https://p0w3rsh3ll.wordpress.com
     
.EXAMPLE
    .\Get-SysinternalsTools
    Download all the sysinternals tools without a proxy

.EXAMPLE
    .\Get-SysinternalsTools -proxy "http://my.internal.proxy.address"
    Download all the sysinternals tools with a proxy

#>

param
(
[parameter(Mandatory=$false)][System.URI]$Proxy=$null,
[parameter(Mandatory=$false)][System.Management.Automation.PSCredential]$ProxyCredential=$null
)
$otherparams = @{}
if ($proxy)
{
    $otherparams += @{Proxy = $Proxy}
    if ($ProxyCredential)
    {
       $otherparams += @{ProxyCredentials = $ProxyCredential}
    }
}

# Define the download URL
$URL = "http://live.sysinternals.com"

# Make sure we can download into the current path + the "live.sysinternals.com" directory 
$targetdir = Join-path -Path (Get-item $pwd) -ChildPath "live.sysinternals.com"
if (-not(Test-path -path $targetdir))
{
    # Create directory
    try
    {
        New-Item -Path $targetdir -itemtype directory -force -ErrorAction SilentlyContinue | Out-Null
    } 
    catch
    {
        Write-Host -ForegroundColor Red -Object ("Error cannot create destination directory live.sysinternals.com into current path $pwd")
        exit 1
    }
}

# Make sure it is a directory
if ((Get-item -Path $targetdir) -isnot [System.IO.DirectoryInfo])
{
    Write-Host -ForegroundColor Red -Object ("Oops, $targetdir exits but it is not a directory")
    exit 1
}

# Here we go: get all the links from the main page
try
{
    $wr = (Invoke-WebRequest -Uri $URL -ErrorAction SilentlyContinue @otherparams)
}
catch
{
    $_
    exit 1
}

$links = $wr.Links

# Cycle through all these links
foreach ($link in $links)
{
    # Show some progress activity as it can be quiet long...
    $i++
    Write-Progress -activity "Dealing with link: $($link.href)" -status "Percent added: " -PercentComplete (($i/$links.Count)*100)

    # Make sure we avoid directories and download a file
    if ($link.href -notmatch "^/.*/$")
    {
        $content = $wrq = $null
        # Write-Host -ForegroundColor DarkCyan -Object ("Downloading $($link.InnerText)")
        
        try
        {
            $wrq = (Invoke-WebRequest -Uri ($URL+$link.href) -Method GET -ErrorAction SilentlyContinue @otherparams)
        } 
        catch
        {
            # Write-Host -ForegroundColor Red -Object ("Failed to download $($link.InnerText)")
        }
        
        if ($wrq.StatusCode -eq 200)
        {
            $content = $wrq.Content
            $encoding = $null
            # http://en.wikipedia.org/wiki/Mime_type
            # http://technet.microsoft.com/en-us/library/dd347719.aspx
            switch ($wrq.Headers['Content-Type'])
            {
                "text/plain"               { $encoding = [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding]::string  ; break }
                "application/octet-stream" { $encoding = [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding]::byte    ; break }
                default                    { $encoding = [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding]::unknown ; break }
            } # end of switch

            # Save the content that is a system.byte array to a file
            Set-content -value $content -encoding $encoding -path ($targetdir + $link.href)
        }
    }
}

# Now loop and let us know what file is being updated and those remaining identical
Get-ChildItem $targetdir | ForEach-Object {
    if (Test-path (Join-path -path (Get-item $targetdir).PSParentPath -ChildPath $_.Name))
    {
        $newfileversion = $_.VersionInfo.Fileversion
        $oldfileversion = (Get-item (Join-path -path (Get-item $targetdir).PSParentPath -ChildPath $_.Name)).VersionInfo.Fileversion

        if ($newfileversion -ne $oldfileversion)
        {
            Copy-Item -Path $_.Fullname -Destination (Get-item $targetdir).PSParentPath -Force # -Confirm:$true
            Write-Host -ForegroundColor Green -Object ($_.Name + " updated from " + $oldfileversion + " -> " + $newfileversion)
        } else {
            Write-Host -ForegroundColor Green -Object ($_.Name + " identical")
        }
    }
} # end of foreach

The interesting thing with this script is that we can see “nested” (let’s say more than 1) write-progress bars in the console output while it downloads files. Among other interesting things, you have the splatting technique to handle script arguments and the ‘[system.URI]’ .net object being preserved that nicely handles the port specified in the URL.
system.URI

The following image shows the final output we get:
get-sysinternalstools output

I’ve also left inside the script a link to the get-content cmdlet help page where Joel -Jaykul- Bennett and Thomas Lee updated the documentation about the -encoding parameter of the set-content cmdlet. Jason Fossen also shows on this page how to use the set-content cmdlet with the -encoding parameter:
http://www.sans.org/windows-security/2010/02/11/powershell-byte-array-hex-convert.
So let me say, Thank you guys :-).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s