posh-gist.ps1
Function Get-CredentialBasic { <# .Synopsis Outputs BASIC credentials. .INPUTS PSCredential .OUTPUTS string .NOTES The accepted credentials is either your Github username/password pair, or, preferably, your username and a token created at https://github.com/settings/tokens The PSCredential object has to be decoded as Github breaks RFC2617 and never sends the needed HTTP code. See https://developer.github.com/v3/auth/#basic-authentication .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding()] Param ( # Credentials. See notes. [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)] [Alias('Cred')] [PSCredential]$Credential ) $BasicString = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password) $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BasicString) $auth = '{0}:{1}' -f $Credential.UserName,$UnsecurePassword $bytes = [System.Text.Encoding]::ASCII.GetBytes($auth) $base64 = [System.Convert]::ToBase64String($bytes) Return 'Basic {0}' -f $base64 } Function Get-Gist { <# .Synopsis Retrieves Github gists .DESCRIPTION Retrieves gists, either public ones or for the current user. Optionally writes the files contained in the gist to the disk. .EXAMPLE Get-Gist Retrieves the most recent public gists. .EXAMPLE Get-Gist -Credential ( Get-Credential ) Retrieves the current users gists. .EXAMPLE Get-Gist -User johndoe -Since 2016-03-03 Retrieves johndoe's gist updated after the given date. .EXAMPLE Get-Gist -Credential $cred -Starred Retrieves gists starred by the current user. .EXAMPLE Get-Gist -Id 5e85af5998abf08f2d86c9aef968ef9f -Forks Retrieves the forks of a specific gist. .EXAMPLE Get-Gist -User johndoe | select -First 1 | Get-Gist -File * -Destination out Retrieves johndoe's last gist and outputs the files in the 'out' folder. .INPUTS System.String You can pipe strings that contains gists Ids. posh-gist.gist You can pipe the custom object posh-gist.gist (type output by the poshgist CMDlets) .OUTPUTS posh-gist.gist Get-Gists outputs a custom object type that contains all information pertaining to a gist. The CMDlet returns $false when an error occured. .NOTES The accepted credentials is either your Github username/password pair, or, preferably, your username and a token created at https://github.com/settings/tokens .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding(DefaultParameterSetName='User')] Param ( # To retrieves the gists of the selected user. [Parameter(ParameterSetName='User')] [string[]]$User, # Limits the gists to the ones updated after the given date. [Parameter(ParameterSetName='User')] [string]$Since, # Retrieves gists by Id. [Parameter(ParameterSetName='Id',ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)] [Parameter(ParameterSetName='Forks',Mandatory=$true)] [string[]]$Id, # To retrieves a specific revision of the gist. [Parameter(ParameterSetName='Id')] [string]$Sha, # Select files from the gist to be written to disk. # Wildcard permitted (IE. '*.txt' to get all text files) [Parameter(ParameterSetName='Id')] [string[]]$File, # Folder to write the files to. Will be created if needed. Defaults to current folder. [Parameter(ParameterSetName='Id')] [string]$Destination, # Overwrites files if they already exist. [Parameter(ParameterSetName='Id')] [switch]$Force, # To retrieves the forks of a specific gist. [Parameter(ParameterSetName='Forks',Mandatory=$true)] [switch]$Forks, # To retrieves the last public gists. [Parameter(ParameterSetName='Public')] [switch]$Public, # To retrieves the gists starred by the current user. [Parameter(ParameterSetName='Starred')] [switch]$Starred, # Credentials. See notes. [Alias('Cred')] [PSCredential]$Credential #FIXME #[int[]]$Page ) Begin { $headers = @{} If ( $Credential ) { $headers.Authorization = Get-CredentialBasic -Credential $Credential } $parameters = @() If ( $Since ) { $parameters += 'since={0}' -f ( Get-Date -Date $Since -Format s ) } if ($parameters.count) { $reqparameters = '?' + ( $parameters -join '&' ) } If ( $Destination -and ( -not $File ) ) { $File = '*' } } Process { If ( $Public ) { $URI = 'https://api.github.com/gists/public' } elseIf ( $Starred ) { $URI = 'https://api.github.com/gists/starred' } elseIf ( $Forks ) { $URI = 'https://api.github.com/gists/{0}/forks' -f $Id } elseIf ( $Id ) { $URI = 'https://api.github.com/gists/{0}' -f $Id If ( $Sha ) { $URI += '/' + $Sha } } ElseIf ( $User ) { $URI = 'https://api.github.com/users/{0}/gists' -f $User } Else { $URI = 'https://api.github.com/gists' } Try { $WebRequest = Invoke-WebRequest -Headers $headers -Uri ( $URI + $reqparameters ) -Method Get $gists = ConvertFrom-Json -InputObject $WebRequest.content foreach ($gist in $gists) { $gist.PSTypeNames.Insert(0,'posh-gist.gist') } $outfiles = @() foreach ( $filename in $File ) { If ( $filename -notmatch '[*?]' ) { $outfiles += $filename } Else { $regexp = [Regex]::Escape($filename) -replace '\\\*','.*' -replace '\\\?','.' $outfiles += $gist.files.psobject.Properties | ? name -Match $regexp | select -ExpandProperty name } } foreach ( $OutFile in ( $outfiles | select -Unique ) ) { If ( $gist.files."$OutFile" ) { $DestinationPath = Join-Path -Path $Destination -ChildPath $OutFile If ( ( Test-Path -Path $DestinationPath ) -and ( -not $Force ) ) { Throw '{0} already exists. Use -Force to overwrite' -f $DestinationPath } Else { If ( $gist.file."$OutFile".truncated ) { $content = Invoke-WebRequest -Uri $tg.files.'poshgist.ps1'.raw_url | select -ExpandProperty content } Else { $content = $gist.files."$OutFile".content } If ( -not ( Test-Path -Path $Destination ) ) { $null = New-Item -Path $Destination -ItemType directory } Out-File -FilePath $DestinationPath -InputObject $content -Force # Trade-off. Getting the real timestamp of every file would require analysing history (Get-Item -Path $DestinationPath).LastWriteTime = $gist.updated_at } } Else { Throw '{0} was not found in the gist.' -f $OutFile } } Return $gists } Catch { Write-Host -Object $_.Exception.Message Return $false } } } Function New-Gist { <# .Synopsis Creates a Github gist .DESCRIPTION Creates a gist by including files, or by forking an existing one. .EXAMPLE New-Gist -file poshgist.*,readme.txt -Description 'Gist management CMDlets' -Public Creates a gist containing the selected files. .EXAMPLE New-Gist -Fork 5e85af5998abf08f2d86c9aef968ef9f Forks a gist. Forks are always public. .INPUTS None. You cannot pipe anything to New-Gist. .OUTPUTS posh-gist.gist New-Gists outputs a custom object type that contains all information pertaining to the new gist. The CMDlet returns $false when an error occured. .NOTES The accepted credentials is either your Github username/password pair, or, preferably, your username and a token created at https://github.com/settings/tokens .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding()] Param ( # Files to include in the gist. Wildcard are permitted. [Parameter(ParameterSetName='New',Mandatory=$true,ValueFromPipeline=$true,Position=0)] [Parameter(ParameterSetName='Anonymous',Mandatory=$true)] [string[]]$Path, # Description of the gist. [Parameter(ParameterSetName='New')] [Parameter(ParameterSetName='Anonymous')] [string]$Description, # Creates a public gist. The default option is a secret one. [Parameter(ParameterSetName='New')] [Parameter(ParameterSetName='Anonymous')] [switch]$Public, # Creates an anonymous gist. [Parameter(ParameterSetName='Anonymous',Mandatory=$true)] [switch]$Anonymous, # The id of the gist to fork. [Parameter(ParameterSetName='Fork',Mandatory=$true)] [string]$Fork, # Credentials. See notes. [Alias('Cred')] [Parameter(ParameterSetName='Fork')] [Parameter(ParameterSetName='New',Mandatory=$true)] [PSCredential]$Credential ) Begin { $Body = @{} $Files = @{} If ( $Description ) { $Body.description = $Description } If ( $Public ) { $Body.public = $true } If ( $Credential ) { $headers = @{ Authorization = Get-CredentialBasic -Credential $Credential } } } Process { If ( -not $Fork ) { $FileList = Get-Item -Path $Path foreach ( $File in $FileList ) { $Files[$File.Name] = @{content=( Get-Content $File -Encoding UTF8 | Out-String )} } } } End { If ( $Fork ) { Try { $Uri = 'https://api.github.com/gists/92fa6e65eacf26219022/forks' $RawReq = Invoke-WebRequest -Headers $headers -Uri $Uri -Method Post $Req = ConvertFrom-Json -InputObject $RawReq $Req.PSTypeNames.Insert(0,'posh-gist.gist') Return $Req } Catch { Write-Host -Object $_.Exception.Message Return $false } } Else { Try { $Body.files = $Files $json = ConvertTo-Json -InputObject $Body $json = [System.Text.Encoding]::UTF8.GetBytes($json) $RawReq = Invoke-WebRequest -Headers $headers -Uri https://api.github.com/gists -Method Post -Body $json $Req = ConvertFrom-Json -InputObject $RawReq $Req.PSTypeNames.Insert(0,'posh-gist.gist') Return $Req } Catch { Write-Host -Object $_.Exception.Message Return $false } } } } Function Remove-Gist { <# .Synopsis Deletes a Github gist .DESCRIPTION Deletes a gist by ID. You must be authenticated. .EXAMPLE Remove-Gist -Id <gist id> -Credential ( Get-Credential ) Deletes the gist. .INPUTS None. You cannot pipe anything to New-Gist. .OUTPUTS Boolean Remove-Gists returns true if the gist was deleted. False otherwise. .NOTES The accepted credentials is either your Github username/password pair, or, preferably, your username and a token created at https://github.com/settings/tokens .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding()] Param ( # Id of the gist to delete. [Parameter(ParameterSetName='Id',ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)] [string[]]$Id, # Credential. Mandatory, as you can only delete your own gists. [Parameter(Mandatory=$true)] [Alias('Cred')] [PSCredential]$Credential ) Begin { If ( $Credential ) { $headers = @{ Authorization = Get-CredentialBasic -Credential $Credential } } } Process { Try { $Uri = 'https://api.github.com/gists/{0}' -f $Id Invoke-WebRequest -Headers $headers -Uri $Uri -Method Delete Return $true } Catch { Write-Host -Object $_.Exception.Message Return $false } } } Function Update-Gist { <# .Synopsis Updates a Github gist .DESCRIPTION Updates a gist by adding, removing, updating or renoming files. .EXAMPLE Update-Gist -id 5e85af5998abf08f2d86c9aef968ef9f -Update poshgist.ps1 -Add poshgist.md Updates poshgist.ps1 in the gist, and adds poshgist.md .EXAMPLE Update-Gist -id 5e85af5998abf08f2d86c9aef968ef9f -Remove *.txt Removes text files from the gist. .EXAMPLE Update-Gist -id 5e85af5998abf08f2d86c9aef968ef9f -Rename readme.txt -Destination readme.md Renames the file in the gist. .EXAMPLE Update-Gist -id 5e85af5998abf08f2d86c9aef968ef9f -Description 'My oh so very nice gist' Adds or changes the gist's description .EXAMPLE Update-Gist -id 5e85af5998abf08f2d86c9aef968ef9f -Star Stars a gist. Go on, try it. .INPUTS System.String You can pipe strings that contains gists Ids. posh-gist.gist You can pipe the custom object posh-gist.gist (type output by the poshgist CMDlets) .OUTPUTS posh-gist.gist New-Gists outputs a custom object type that contains all information pertaining to the updated gist. The CMDlet returns $false when an error occured. .NOTES The accepted credentials is either your Github username/password pair, or, preferably, your username and a token created at https://github.com/settings/tokens .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding()] Param ( # Id of the gists to update [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)] [string[]]$Id, # Description of the gist [Parameter(ParameterSetName='Update')] [string]$Description, # File(s) to add to the gist [Parameter(ParameterSetName='Update')] [string[]]$Add, # File(s) to update in the gist [Parameter(ParameterSetName='Update')] [string[]]$Update, # File(s) to remove from the gist [Parameter(ParameterSetName='Update')] [string[]]$Remove, # File(s) to rename in the gist [Parameter(ParameterSetName='Update')] [string[]]$Rename, # New name(s) for the file(s) in the gist [Parameter(ParameterSetName='Update')] [string[]]$Destination, # Stars a gist. Can belong to another user. [Parameter(ParameterSetName='Star')] [switch]$Star, # Unstars a gist. Can belongs to another user. [Parameter(ParameterSetName='Unstar')] [switch]$Unstar, [Parameter(Mandatory=$true)] # Credential. Mandatory, as you can only modify your own gists, and stars are per account. [Alias('Cred')] [PSCredential]$Credential ) Begin { $headers = @{} If ( $Credential ) { $headers.Authorization = Get-CredentialBasic -Credential $Credential } $Files = @{} } Process { If ( $Star ) { Try { $Uri = 'https://api.github.com/gists/{0}/star' -f $Id $headers.'Content-Length' = 0 Invoke-WebRequest -Headers $headers -Uri $Uri -Method Put Return $true } Catch { Write-Host -Object $_.Exception.Message Return $false } } Elseif ( $Unstar ) { Try { $Uri = 'https://api.github.com/gists/{0}/star' -f $Id Invoke-WebRequest -Headers $headers -Uri $Uri -Method Delete Return $true } Catch { Write-Host -Object $_.Exception.Message Return $false } } Else { $Body = @{} If ( $Description ) { $Body.description = $Description } If ( $Add ) { $FileList = Get-Item -Path $Add foreach ( $File in $FileList ) { $Files[$File.Name] = @{content=( Get-Content $File -Encoding UTF8 | Out-String )} } } If ( $Update ) { $FileList = Get-Item -Path $Update foreach ( $File in $FileList ) { $Files[$File.Name] = @{content=( Get-Content $File -Encoding UTF8 | Out-String )} } } If ( $Remove ) { foreach ( $filename in $Remove ) { $Files[$filename] = $null } } If ( $Rename ) { If ( $Rename.count -eq $Destination.count ) { foreach ( $i in ( 0..($Rename.Count -1) ) ) { $Files[$Rename[$i]] = @{filename=$Destination[$i]} } } Else { Throw '-Rename and -Destination must include the same number of elements.' } } If ( $Files.count -ne 0 ) { $Body.files = $Files } # $Body # ConvertTo-Json $Body Try { $Uri = 'https://api.github.com/gists/{0}' -f $Id $json = ConvertTo-Json -InputObject $Body $json = [System.Text.Encoding]::UTF8.GetBytes($json) $RawReq = Invoke-WebRequest -Headers $headers -Uri $Uri -Method Patch -Body $json $Req = ConvertFrom-Json -InputObject $RawReq $Req.PSTypeNames.Insert(0,'posh-gist.gist') Return $Req } Catch { Write-Host -Object $_.Exception.Message Return $false } } } } Function Get-GistCommits { <# .Synopsis Retrieves a Github gist history .DESCRIPTION Retrieves a list of commits for a gist. .EXAMPLE Get-GistCommits -Id 5e85af5998abf08f2d86c9aef968ef9f Retrieves the commits history of a specific gist. .INPUTS System.String You can pipe strings that contains gists Ids. posh-gist.gist You can pipe the custom object posh-gist.gist (type output by the poshgist CMDlets) .OUTPUTS posh-gist.gistcommit Get-GistsCommits outputs a custom object type that contains all information pertaining to commits. The CMDlet returns $false when an error occured. .NOTES Commits get their own CMDlets because it has a different output format. .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding()] Param ( # Id of the gists to history of. [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)] [string]$Id ) $Uri = 'https://api.github.com/gists/{0}/commits' -f $Id Try { $Req = Invoke-WebRequest -Uri $Uri $Commits = ConvertFrom-Json -InputObject $Req.content foreach ($commit in $Commits) { $commit.PSTypeNames.Insert(0,'posh-gist.gistcommit') } Return $Commits } Catch { Write-Host -Object $_.Exception.Message Return $false } } Function Get-GistStar { <# .Synopsis Retrieves a Github gist starred status .DESCRIPTION Retrieves a gist's the starred status for the current user. .EXAMPLE Get-GistStar -Id 5e85af5998abf08f2d86c9aef968ef9f -Credential $cred Check whether you starred the gist or not. .INPUTS System.String You can pipe a string that contains the gist Id. posh-gist.gist You can pipe the custom object posh-gist.gist (type output by the poshgist CMDlets) .OUTPUTS Boolean Get-GistStar outputs $true if the gist is starred. $false otherwise. .NOTES The accepted credentials is either your Github username/password pair, or, preferably, your username and a token created at https://github.com/settings/tokens .COMPONENT poshgist .LINK https://gist.github.com/XPlantefeve/5e85af5998abf08f2d86c9aef968ef9f #> [CmdletBinding()] Param ( # Id of the gist to history of. [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)] [string]$Id, # Credentials. Mandatory as stars are a per-user thing. [Parameter(Mandatory=$true)] [Alias('Cred')] [PSCredential]$Credential ) $headers = @{} $headers.Authorization = Get-CredentialBasic -Credential $Credential $Uri = 'https://api.github.com/gists/{0}/star' -f $Id Try { $Req = Invoke-WebRequest -Uri $Uri -Headers $headers Return $true } Catch { Return $false } } |