Cuma Eğlencesi: SysInternals PowerShell İş Akışı


Yıllar geçtikçe SysInternals araçlarını masaüstüme indirmek için bir dizi PowerShell aracı geliştirdim. Ve evet, PowerShell 5 ve PowerShellGet ile SysInternals paketini indirip yükleyebileceğimi biliyorum. Ancak bu, paketin güncel olduğunu varsayar. Ama asıl mesele bu değil. Bunun yerine, size bir iş akışını komut dosyası oluşturma aracı olarak kullanmanın bir örneğini sunmak için bugünkü Cuma Eğlencesini kullanmak istiyorum. Bu durumda amaç SysInternals dosyalarını internetten indirmektir.

Öncelikle GitHub'dan iş akışının bir kopyasını almanız gerekecek.

Update-SysinternalsWorkflow.ps1:

#requires -version 4.0

#https://gist.github.com/jdhitsolutions/f0415db6bc8dc6236fb3

<#
A PowerShell workflow to download Sysinternals tools from web to a local folder.

Last updated: February 15, 2016
version     : 2.1

Changelog:
 2.0
 Moved path validation to a sequence step
 If destination doesn't exist it will be created.
 Modified activities to make them compatible with PowerShell 3.0
 Added error handling for starting the Webclient service
 Tested and verified remote processing
 combined a few sequences to avoid scoping problems
 Added code to download a list of online files and then compare instead of trying to 
 get each file online individually and then compare.
 Tested remote installation
 Modified version requirement to v4 since I have no v3 clients left to test with
 
 2.1
 Added detailed progress information
 Added Passthru parameter and changed default behavior to not display files as they are copied

 
Learn more about PowerShell:
http://jdhitsolutions.com/blog/essential-powershell-resources/

  ****************************************************************
  * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
  * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK.  IF   *
  * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
  * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING.             *
  ****************************************************************
#>

Workflow Update-SysInternals {
[cmdletbinding()]
Param(
[Parameter(Position = 0,Mandatory,HelpMessage = "Enter a folder path")]
[Alias("Path")]
[string]$Destination,
[switch]$Passthru
)

Sequence {
    #Validate path
    Write-Verbose -Message "Validating destination path $Destination"  
   
    if (Test-Path -Path $Destination -DisplayName "Testing Path") {

        Write-Verbose -Message "Destination $Destination already exists"
        
    } #if test-path
    else {
       
       #Create the folder
        Try {
            Write-Verbose -message "Creating $Destination"
            New-Item -Path $Destination -ItemType Directory -ErrorAction Stop -PSProgressMessage "Creating $Destination"
        }
        Catch {
            Write-Warning -Message "Failed to create $Destination. $($_.Exception.message)"
            #Can't create the folder so bail out
            Return
        }

    } #else
}

Sequence {
    #Verify there is webclient service installed
    Write-Verbose -Message "Verifying WebClient service is available"
    Try {
        $test = Get-Service -Name Webclient -ErrorAction Stop -PSProgressMessage "Getting Webclient service"
    }
    Catch {
        Write-Warning "Could not find the WebClient service. Aborting."
        #Bail out
        Return
    }

}

Sequence {
    #start the WebClient service if it is not running
    Write-Verbose -message "Checking status of WebClient service"
    if ((Get-Service -name WebClient).Status -eq 'Stopped') {
         Write-Verbose -message "Starting WebClient"
         Try {
            Start-Service -name WebClient -ErrorAction Stop -PSProgressMessage "Starting WebClient"
            $workflow:Stopped = $True
         }
         Catch {
            Write-Warning "Failed to start WebClient service. $($_.exception.message)"
            #can't start service so bail out
            Return
         }
    }
    else {
        <#
         Define a variable to indicate service was already running
         so that we don't stop it. Making an assumption that the
         service is already running for a reason.
        #>
        Write-Verbose -Message "Service is already running"
        $Workflow:Stopped = $False
    }

    Write-Verbose -Message (Get-Service -Name WebClient | Out-String)
   
}

Sequence {

    #get current files in destination
    Write-Verbose -message "Getting current listing of files from $Destination"
    $current = Get-Childitem -Path $Destination -File -DisplayName "Getting current files"
    
    Write-Verbose -message "Creating a list of online files"

    #dowload list of files
    $webfiles = Get-ChildItem -Path "\\live.sysinternals.com\tools" -file -DisplayName "Getting online files" -PSProgressMessage "...this might take a little time"
    
    if (-NOT $webfiles) {
        Write-Warning "No webfiles found"
        #if no online files found something went wrong so bail out.
        RETURN
    }
       
    Write-Verbose -Message "Found $($webfiles.count) online files"   

    #download files in parallel groups of 8
    Write-Verbose -message "Updating Sysinternals tools from \\live.sysinternals.com\tools to $destination"

    foreach -parallel -throttle 8 ($file in $current) {
        #get the web version
        Write-Verbose -Message "Testing $($file.Name)"
        
        $online = $($webfiles).Where({$_.name -eq $file.name})
        
        if ($online.LastWriteTime.date -gt $file.lastWriteTime.date) {
            Write-Verbose -Message "Copying $($online.fullname)"
            Copy-Item -Path $online.fullname -Destination $Destination -PassThru:$Passthru -DisplayName "Downloading files" -PSProgressMessage $online.fullname
        }

    } #foreach

    Write-Verbose -message "Testing for online files not in $destination"

    #test for files online but not in the destination and copy them
    #compare to current list and get a list of file names that are missing
    $names = Compare-Object -ReferenceObject $webfiles -DifferenceObject $current -Property Name -DisplayName "Comparing files" | 
    Select-object -ExpandProperty Name
    foreach -parallel -throttle 8 ($file in $names) {
        Get-Item -path "\\live.sysinternals.com\tools\$file" -DisplayName "Downloading missing files" -PSProgressMessage $file | 
        Copy-Item -Destination $Destination -PassThru:$Passthru 
    }
    
    if ( $workflow:Stopped ) {
        Write-Verbose -message "Stopping web client"
        Stop-Service -name WebClient -PSProgressMessage "Stopping WebClient"
            $workflow:Stopped = $True
    }

    Write-Verbose "Sysinternals Update Complete"
} 

} #end workflow

<#
Copyright (c) 2016 JDH Information Technology Solutions, Inc.


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:


The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
#>

İş akışı komutu bir işleve benzer; dosyayı nokta kaynak olarak kullanmak gibi onu PowerShell oturumunuza yüklemeniz gerekir.

. c:\scripts\Update-SysinternalsWorkflow.ps1

Bu size yeni bir komut verecektir.

İş akışı artık diğer komutlar gibi yürütülebilir.

İş akışının temel avantajı, öğeleri paralel olarak işleyebilmesi ve etkinliği kısıtlayabilmenizdir. İş akışımda aynı anda 8 dosya işliyorum.

Sequence {
Write-Verbose "Updating Sysinternals tools from \\live.sysinternals.com\tools to $destination"

#download files in parallel groups of 8
foreach -parallel -throttle 8 ($file in $current) {
  #construct a path to the live web version and compare dates
  $online = Join-Path -path \\live.sysinternals.com\tools -ChildPath $file.name
  Write-Verbose "Testing $online"
  if ((Get-Item -Path $online).LastWriteTime.Date -ge $file.LastWriteTime.Date) {
    Copy-Item $online -Destination $Destination -PassThru
  }
}
}

İş akışında dikkat edilmesi gereken şeylerden biri kapsamdır. Değişkenlere tüm iş akışı boyunca erişilebileceğini varsaymamalısınız. Bu yüzden bazı değişkenlerin kapsamını özellikle belirliyorum, böylece diziler boyunca kalıcı olacaklar.

Gerçekten bir gün paralel işlemenin dile de gireceğini umuyorum çünkü açıkçası iş akışını kullanmamın tek nedeni bu. Ve hızlıdır. Dizinin tamamını FiOS bağlantıma bir dakikadan biraz daha uzun bir sürede indirdim. İş akışı ayrıca yalnızca çevrimiçi olarak daha yeni olan veya belirtilen dizinde olmayan dosyaları indirecektir.

İş akışları hakkında daha fazla bilgi edinmek istiyorsanız PowerShell'de Derinlemesine materyaller bulunmaktadır.

Umarım bunu faydalı bulursunuz. Bunu senin için sevgilim olarak düşün.

NOT: Komut dosyası GitHub'da olduğundan, bu yazıya gömülü olarak gördükleriniz de dahil olmak üzere her zaman en son sürüm olacaktır. Bu makalenin yayınlanmasından bu yana, bu makaleye her zaman yansımayabilecek birkaç değişiklik yaptım.

İlgili makaleler