Public/Get-GitHubUserRepos.ps1
function Get-GitHubUserRepos { <# .Synopsis Download GitHub User Gists & Repositories .DESCRIPTION Uses git.exe to clone the gists and repositories of a github user. Can Exclude repositories with names that match the string/strings defined with -Exclude Requires Module - PowerShellForGitHub Requires git.exe I included the source file for PForEach because it is no longer visible in the powershellgallery and github Vasily Larionov - https://www.powershellgallery.com/profiles/vlariono | https://github.com/vlariono PForEach - https://www.powershellgallery.com/packages/PForEach .EXAMPLE Get-GitHubUserRepos -UserName WozNet -Path 'V:\git\users' -Exclude 'docs' .EXAMPLE 'WozNet','PowerShell','Microsoft' | Get-GitHubUserRepos -Path 'V:\git\users' -Exclude 'azure,'office365' #> [CmdletBinding()] [Alias('dlgit')] Param( # Param1 help - GitHub Usernames [Parameter( Mandatory, HelpMessage='Github UserName', ValueFromPipeline )] [ValidateNotNullOrEmpty()] [String[]]$UserName, # Param2 help - Directory to save User Gists and Repositories [ValidateScript({ Test-Path -Path $_ -PathType Container })] [String]$Path = 'V:\git\users', # Param3 help - Exclude Repositories with Names matching these strings [String[]]$Exclude = 'docs', # Param4 help - ThrottleLimit for Invoke-ForEachParallel [int]$ThrottleLimit = 5 ) Begin { ##### Load Progress helper function function Write-MyProgress { <# .SYNOPSIS Displays a progress bar within a Windows PowerShell command window. .DESCRIPTION The Write-Progress cmdlet displays a progress bar in a Windows PowerShell command window that depicts the status of a running command or script. .NOTES File Name : Write-MyProgress.ps1 Author : Woz Date : 2017-05-10 Last Update : 2023-01-14 Version : 2.0.0 .PARAMETER id Specifies an ID that distinguishes each progress bar from the others. .PARAMETER ParentId Specifies the parent activity of the current activity. .PARAMETER StartTime StartTime of the foreach processing .PARAMETER Object Object use in your foreach processing .PARAMETER Count Foreach Count variable .EXAMPLE $GetProcess = Get-Process $Count = 0 $StartTime = Get-Date foreach($Process in $GetProcess) { $Count++ Write-MyProgress -StartTime $StartTime -Object $GetProcess -Count $Count Write-Host "-> $($Process.ProcessName)" Start-Sleep -Seconds 1 } .LINK Source https://github.com/Netboot-France/Write-MyProgress #> Param( [Parameter(Mandatory)] [Array]$Object, [Parameter(Mandatory)] [DateTime]$StartTime, [Parameter(Mandatory)] [Int]$Count, [Int]$Id=1, [Int]$ParentId=-1 ) $SecondsElapsed = ((Get-Date) - $StartTime).TotalSeconds $SecondsRemaining = ($SecondsElapsed / ($Count / $Object.Count)) - $SecondsElapsed $PercentComplete = ($Count/$($Object.Count)) * 100 $Argument = @{} $Argument.Add('Activity', ('Processing {0} of {1}' -f $Count, $Object.Count)) $Argument.Add('PercentComplete', $PercentComplete) $Argument.Add('CurrentOperation', ('{0:N2}% Complete' -f $PercentComplete)) $Argument.Add('SecondsRemaining', $SecondsRemaining) if($Id -ne $null) { $Argument.Add('Id', $Id) } if($ParentId -ne $null) { $Argument.Add('ParentId', $ParentId) } Write-Progress @Argument } ##### try{ if (-not (Get-Command -Name git.exe)) { throw 'git.exe is missing' } if (-not (Get-Module -ListAvailable -Name PowerShellForGitHub)) { throw 'Install Module - PowerShellForGitHub' } Import-Module -Name PowerShellForGitHub -PassThru:$false if (-not (Get-Command -Name Invoke-ForEachParallel -ErrorAction SilentlyContinue)) { # Import-Module -Name (Join-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -ChildPath 'Lib\PForEach\PForEach.dll' -Resolve) -PassThru:$false -ErrorAction Stop Import-Module -Name ([System.IO.Path]::Combine((Split-Path -Path $PSScriptRoot -Parent),'Lib\PForEach\PForEach.dll')) -PassThru:$false -ErrorAction Stop } if (-not (Get-GitHubConfiguration -Name DisableTelemetry)) { Set-GitHubConfiguration -DisableTelemetry } if (-not (Test-GitHubAuthenticationConfigured)) { $Host.UI.WriteErrorLine('PowerShellForGitHub is not Authenticated') } } catch { [System.Management.Automation.ErrorRecord]$e = $_ [PSCustomObject]@{ Type = $e.Exception.GetType().FullName Exception = $e.Exception.Message Reason = $e.CategoryInfo.Reason Target = $e.CategoryInfo.TargetName Script = $e.InvocationInfo.ScriptName Line = $e.InvocationInfo.ScriptLineNumber Column = $e.InvocationInfo.OffsetInLine } throw $_ } $HTML = @' <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script> <div id="ph"></div> <script> var username = '---' $.getJSON('https://api.github.com/users/' + username + '/gists', function (data) { for (var i in data) { var oldDocumentWrite = document.write document.write = function (scr_content) { for (var i in data) { if ( $.trim( $("#" + data[i].id ).text() ).length == 0 ) { $("#" + data[i].id ).append(scr_content); return; } } } var scr = document.createElement('script'); scr.src = 'https://gist.github.com/' + username + '/' + data[i].id + '.js'; $("#ph").append("<div><h2>" + data[i].description + "</h2></div>"); $("#ph").append(scr.outerHTML); $("#ph").append('<div id="' + data[i].id + '"></div>'); } document.write = oldDocumentWrite; }); </script> '@ $UserPathList = [System.Collections.Generic.List[string]]@() $StopWatch = [System.Diagnostics.Stopwatch]::New() $StopWatch.Start() } Process { $DelDir = [System.Collections.Generic.List[string]]@() foreach ($GitUser in $UserName) { $UserPath = [System.IO.Path]::Combine($Path,$GitUser) if (Test-Path -Path $UserPath -PathType Container) { Get-GitHubRepository -OwnerName $GitUser | Sort-Object -Property updated_at -Descending | ForEach-Object -Process { if ( $LPath = Join-Path -Path $UserPath -ChildPath $_.Name -Resolve -ErrorAction SilentlyContinue | Get-Item ) { [PSCustomObject]@{ Name = $_.Name Git_Updated = $_.updated_at Local_Updated = $LPath.LastWriteTime GetItem = $LPath } } } | Where-Object {$_.Git_Updated -ge $_.Local_Updated} | Select-Object -ExpandProperty GetItem | ForEach-Object { $DelDir.Add($PSItem) } } } if ($DelDir) { Remove-Item -Path $DelDir -Recurse -Force if (Resolve-Path -Path $DelDir -ErrorAction Ignore) { Remove-Item -Path $DelDir -Recurse -Force } } Remove-Variable -Name DelDir -ErrorAction Ignore # Download foreach ($GitUser in $UserName) { $UserPath = [System.IO.Path]::Combine($Path,$GitUser) $UserPathList.Add($UserPath) if (-not (Test-Path -Path $UserPath)) { New-Item -Path $UserPath -ItemType Directory } # Get Gist $UserGist = Get-GitHubGist -UserName $GitUser if ($UserGist) { $GistDir = [System.IO.Path]::Combine($UserPath,'_gist') $TempGistDir = [System.IO.Path]::Combine($UserPath,'_tempgist') if (-not (Test-Path -Path $GistDir)) { New-Item -Path $GistDir -ItemType Directory } if (-not (Test-Path -Path $TempGistDir)) { New-Item -Path $TempGistDir -ItemType Directory } Get-ChildItem -Path $GistDir | Remove-Item -Recurse -Force Set-Content -Value ($HTML.Replace('---',$GitUser)) -Path ([System.IO.Path]::Combine($UserPath,'_gist.html')) -Force Write-Output ('{2}{0} Gists - {1}' -f $GitUser,$UserGist.Count,("`n")) ### Start Downloading Gist to temp dir $Count = 0 $StartTime = Get-Date $UserGist | ForEach-Object -Process { $Count++ Write-MyProgress -StartTime $StartTime -Object $UserGist -Count $Count $UGist = $PSItem Start-Process -WorkingDirectory $TempGistDir -FilePath git.exe -ArgumentList ('clone --recursive {0}' -f $UGist.git_pull_url) -WindowStyle Hidden -Wait $UGist = $null Start-Sleep -Milliseconds 100 } ### Start Moving Gist from temp dir to $GistDir Get-ChildItem $TempGistDir | ForEach-Object { $TGDir = $_ Join-Path -Path $TGDir -ChildPath '.git' -Resolve | Remove-Item -Recurse -Force $TGFiles = $TGDir | Get-ChildItem -Force:$false $TGFileCount = $TGFiles.Count if ($TGFileCount -eq 1) { try { $TGFiles | Move-Item -Destination $GistDir -PassThru:$false -ErrorAction Stop } catch [System.IO.IOException] { @' Shit happened trying to move - {0} Attempting to rename and try moving again '@ -f $TGFiles.Name | Write-Warning $TGFiles | Rename-Item -NewName {$_.Name.Replace($_.BaseName,('{0}-{1}' -f $_.BaseName,$_.Directory.Name.Substring(0,6)))} -PassThru | Move-Item -Destination $GistDir -PassThru:$false -ErrorAction Stop } $MCheck = $TGDir | Get-ChildItem -Force:$false if ($MCheck.Count -eq 0) { Remove-Item -Path $TGDir -Recurse -Force } } else { try { $TGDir | Move-Item -Destination $GistDir -PassThru:$false -ErrorAction Stop } catch [System.IO.IOException] { Write-Error $_ } } } ### Cleaning up Temp Gist Dir Remove-Item -Path $TempGistDir -Recurse -Force } # Get Repo $UserRepo = Get-GitHubRepository -OwnerName $GitUser $FilteredUserRepo = switch ($Exclude.Count) { {$_ -ge 1} { $UserRepo | Where-Object {$_.name -notmatch ($Exclude -join '|')} ; break } default { $UserRepo ; break } } Write-Output ('{0}{1} Repositories - {2} (excluded - {3})' -f "`n",$GitUser,$FilteredUserRepo.Count,($UserRepo.Count - $FilteredUserRepo.Count)) $FilteredUserRepo.name| Select-Object -Property @{e={if ($_.Length -gt 27) {$_.Substring(0,24) + '...'} else{$_}}} | Format-Wide -AutoSize $FilteredUserRepo | Invoke-ForEachParallel -ThrottleLimit $ThrottleLimit -Process { Start-Process -WorkingDirectory $UserPath -FilePath git.exe -ArgumentList ('clone --recursive {0}' -f $PSItem.clone_url) -WindowStyle Hidden -Wait Start-Sleep -Milliseconds 150 $RepoDir = Get-Item -Path (Join-Path -Path $UserPath -ChildPath $PSItem.name -Resolve) $RepoDir.LastWriteTime = $PSItem.updated_at } } } End { $StopWatch.Stop() 'Time - {0:m\:ss}{1}' -f $StopWatch.Elapsed,("`n") 'Updated User Directories:' $UserPathList } } |