#Requires -version 1.0 ## PoshCode module v 3.8 ## See comments for each function for changes ... ############################################################################################################## ## Provides functions for working with scripts from the PoshCode Repository: ## Get-PoshCodeUpgrade - get the latest version of this script from the PoshCode server ## Get-PoshCode - Search for and download code snippets ## New-PoshCode - Upload new code snippets ## Get-WebFile - Download ############################################################################################################## # Set-StrictMode -Version Latest $PoshCode = "http://PoshCode.org/" | Add-Member -type NoteProperty -Name "UserName" -Value "Anonymous" -Passthru | Add-Member -type NoteProperty -Name "ScriptLocation" -Value $($MyInvocation.MyCommand.Path) -Passthru | Add-Member -type NoteProperty -Name "ScriptVersion" -Value 3.8 -Passthru | Add-Member -type NoteProperty -Name "ApiVersion" -Value 1 -Passthru ## New-PoshCode (formerly Send-Paste) ############################################################################################################## ## Uploads code to the PowerShell Script Repository and returns the url for you. ############################################################################################################## ## Usage: ## get-content myscript.ps1 | New-PoshCode "An example for you" "This is just to show how to do it" ## would send the script with the specified title and description ## ls *.ps1 | New-PoshCode -Keep Forever ## would flood the pastebin site with all your scripts, using filename as the title ## and a generic description, and mark them for storing indefinitely ## get-history -count 5 | % { $_.CommandLine } | New-PoshCode ## would paste the last 5 commands in your history! ############################################################################################################## ## History: ## v 3.1 - Fixed the $URL parameter so that it's settable again. *This* function should work on any pastebin site ## v 3.0 - Renamed to New-PoshCode. ## Removed the -Permanent switch, since this is now exclusive to the permanent repository ## v 2.1 - Changed some defaults ## - Added "PermanentPosh" switch ( -P ) to switch the upload to the PowerShellCentral repository ## v 2.0 - works with "pastebin" (including posh.jaykul.com/p/ and PowerShellCentral.com/scripts/) ## v 1.0 - Worked with a special pastebin ############################################################################################################## function New-PoshCode { param( $Title, $Description=$(Read-Host "Please enter a description for this script"), $KeepFor="f", $Language="posh", $Author = $($PoshCode.UserName), $url= $($PoshCode) ) BEGIN { $null = [Reflection.Assembly]::LoadWithPartialName("System.Web") [string]$data = $null; [string]$meta = $null; if($language) { $meta = "format=" + [System.Web.HttpUtility]::UrlEncode($language) # $url = $url + "?" +$lang } else { $meta = "format=text" } do { switch -regex ($KeepFor) { "^d.*" { $meta += "&expiry=d" } "^m.*" { $meta += "&expiry=m" } "^f.*" { $meta += "&expiry=f" } default { $KeepFor = Read-Host "Invalid value for 'KeepFor' parameter. Please specify 'day', 'month', or 'forever'" } } } until ( $meta -like "*&expiry*" ) if($Description) { $meta += "&descrip=" + [System.Web.HttpUtility]::UrlEncode($Description) } else { $meta += "&descrip=" } $meta += "&poster=" + [System.Web.HttpUtility]::UrlEncode($Author) function Send-PoshCode ($meta, $title, $data, $url= $($PoshCode)) { $meta += "&paste=Send&posttitle=" + [System.Web.HttpUtility]::UrlEncode($Title) $data = $meta + "&code2=" + [System.Web.HttpUtility]::UrlEncode($data) $request = [System.Net.WebRequest]::Create($url) $request.ContentType = "application/x-www-form-urlencoded" $request.ContentLength = $data.Length $request.Method = "POST" $post = new-object IO.StreamWriter $request.GetRequestStream() $post.Write($data,0,$data.Length) $post.Flush() $post.Close() # $reader = new-object IO.StreamReader $request.GetResponse().GetResponseStream() ##,[Text.Encoding]::UTF8 # write-output $reader.ReadToEnd() # $reader.Close() write-output $request.GetResponse().ResponseUri.AbsoluteUri $request.Abort() } } PROCESS { switch($_) { { $_ -is [System.IO.FileInfo] } { if(!$Title) { if ($_.Extension.Length -gt 0) { $Title = $_.Name.Remove($_.Name.Length - $_.Extension.Length) } else { $Title = $_.Name } } Write-Verbose $_.FullName Write-Output $(Send-PoshCode $meta $Title $([string]::join("`n",(Get-Content $_.FullName))) $url) } { $_ -is [String] } { if(!$data -and !$Title){ $Title = Read-Host "Give us a title for your post" } $data += "`n" + $_ } ## Todo, handle folders? default { Write-Error "Unable to process $_" } } } END { if($data) { Write-Output $(Send-PoshCode $meta $Title $data $url) } } } ## Get-PoshCode (download Repository script) ############################################################################################################## ## Downloads a specified script from a Pastbin.com based site, by Id ## ### OR ### ## Searches the powershellcentral.com/script site and returns lists of results ## All search terms are automatically surrounded with wildcards ## NOTE: powershellcentral.com currently uses MySql fulltext search syntax... ############################################################################################################## ## Usage: ## Get-PoshCode 184 ## would download the original Send-Paste script to 184.ps1 ## Get-PoshCode Pastebin ## would search the repository for the original Send-Paste pastebin script ## Get-PoshCode 184 -Passthru ## would output the contents of Get-PoshCode to the pipeline ## Get-PoshCode 184 Pastebin.ps1 ## would download the original version of these scripts to Pastebin.ps1 in the current directory ## Get-PoshCode Pastebin | % { Get-PoshCode $_.Id } ## would download all the search results ... ############################################################################################################## ## History: ## v 3.7 - Fixed this? Why was it written that way? It didn't work at all? ## - I added a line to actually SET the id if a number is passed ## - I added a PROCESS{} block to make it handle piped in search results. ## v 3.2 - Added an -Upgrade switch to cause the script to get the latest version of the script. ## v 3.1 - Fixed Description and Link to work correctly on v1 ## - Add "Huddled.PoshCode.ScriptInfo" to TypeInfo, so it can be formatted by a ps1xml ## - Add ConvertTo-Module function to try to rename .ps1 scripts to .psm1 ## - Fixed exceptions thrown by searches which return no results ## - Removed the auto-wildcards!!!! ## NOTE: to get the same results as before you must now put * on the front and end of searches ## This is so that searches on the website work the same as searches here... ## My intention is to improve the website's search instead of leaving this here. ## NOTE: the website currently will not search for words less than 4 characters long ## v 3.0 - Working against the new RSS-based API ## - And using ParameterSets, which work in CTP2 ## v 2.0 - Combined with Find-Poshcode into a single script ## v 1.0 - Working against our special pastebin ############################################################################################################## function Get-PoshCode { param( [string]$query, [string]$SaveAs, [string]$Language="posh", $url = $($PoshCode), [switch]$InBrowser, [switch]$Passthru, [switch]$Upgrade ) PROCESS { if($_ -and $_.psobject.Typenames[0] -eq "Huddled.PoshCode.ScriptInfo") { $query = $_.Id } elseif($_) { Write-Host $_.psobject.Typenames } if($Upgrade) { Get-PoshCodeUpgrade } else { $id = $query -as [int] write-debug "Id: $id" if(!$id) { if( [string]::IsNullOrEmpty($query) ) { $(throw "You must specify a query string, or the id of the paste to get") } if( !(@('text','asp','bash','cpp','csharp','posh','vbnet','xml','all') -contains $Language) ) { throw "Invalid language specified, valid values are: 'text','asp','bash','cpp','csharp','posh','vbnet','xml','all'"; } $results = @(([xml](Get-WebFile "$($url)api$($PoshCode.ApiVersion)/$($query)&lang=$($Language)" -passthru)).rss.channel.GetElementsByTagName("item")) if($results.Count -eq 0 ) { Write-Host "Zero Results for '$query'" -Fore Red -Back Black } else { $results | Select @{n="Id";e={($_.link -replace $url,'') -as [int]}}, @{n="Title";e={$_.title }}, @{n="Author";e={$_.creator }}, @{n="Date";e={$_.pubDate }}, @{n="Link";e={$_.guid.get_InnerText() }}, , @{n="Description";e={"$($_.description.get_InnerText())`n" }} | ForEach { $_.PSObject.TypeNames.Insert( 0, "Huddled.PoshCode.ScriptInfo" ); $_ } } } else { if(!$InBrowser) { filter ConvertTo-Module { $oldFile = $_ if( ([IO.Path]::GetExtension($oldFile) -eq ".ps1") -and [Regex]::Match( [IO.File]::ReadAllText($oldFile), "^[^#]*Export-ModuleMember.*", "MultiLine").Success ) { $fileName = [IO.Path]::ChangeExtension($oldFile, ".psm1") Move-Item $oldFile $fileName -Force Get-Item $fileName } else { $oldFile } } if($SaveAs) { Get-WebFile "$($url)?dl=$id" -fileName $SaveAs | ConvertTo-Module } elseif($Passthru) { Get-WebFile "$($url)?dl=$id" -Passthru } else { Get-WebFile "$($url)?dl=$id" | ConvertTo-Module } } else { [Diagnostics.Process]::Start( "$($url)$id" ) } } } } } ## Get-PoshCodeUpgrade ############################################################################################################## ## Downloads a new PoshCode script version, and archives old versions.. ############################################################################################################## ## History: ## v3.3 - Removes old versions ## v3.2 - First script version with Upgrade function ############################################################################################################## function Get-PoshCodeUpgrade { $VersionFile = [IO.Path]::ChangeExtension( $PoshCode.ScriptLocation, ("{0}{1}" -f $PoshCode.ScriptVersion, [IO.Path]::GetExtension($PoshCode.ScriptLocation))) # Copy it to make sure we don't loose it Copy-Item $PoshCode.ScriptLocation $VersionFile # Remove old ones ... Remove-Item ( [IO.Path]::ChangeExtension( $PoshCode.ScriptLocation, ".*$([IO.Path]::GetExtension($PoshCode.ScriptLocation))") ) -exclude ([IO.Path]::GetFileName($VersionFile)) -Confirm # Finally, get the new one $NewFile = Get-WebFile "$($PoshCode)PoshCode.ps1" -fileName ( [IO.Path]::ChangeExtension( $PoshCode.ScriptLocation, ".INVALID.ps1")) if( Test-Signature $NewFile ) { Move-Item $NewFile $PoshCode.ScriptLocation -Force -passthru . $PoshCode.ScriptLocation } else { Write-Error "Signature is Not Valid on new version." Get-Item $NewFile } } ## Get-WebFile (aka wget for PowerShell) ############################################################################################################## ## Downloads a file or page from the web ## History: ## v3.8 - Add UserAgent calculation and parameter ## v3.7 - Add file-name guessing and cleanup ## v3.6 - Add -Passthru switch to output TEXT files ## v3.5 - Add -Quiet switch to turn off the progress reports ... ## v3.4 - Add progress report for files which don't report size ## v3.3 - Add progress report for files which report their size ## v3.2 - Use the pure Stream object because StreamWriter is based on TextWriter: ## it was messing up binary files, and making mistakes with extended characters in text ## v3.1 - Unwrap the filename when it has quotes around it ## v3 - rewritten completely using HttpWebRequest + HttpWebResponse to figure out the file name, if possible ## v2 - adds a ton of parsing to make the output pretty ## added measuring the scripts involved in the command, (uses Tokenizer) ############################################################################################################## function Get-WebFile { param( $url = (Read-Host "The URL to download"), $fileName = $null, [switch]$Passthru, [switch]$quiet, [string]$UserAgent = "PoshCode/$($PoshCode.ScriptVersion)" ) Write-Verbose "Downloading '$url'" $req = [System.Net.HttpWebRequest]::Create($url); $req.UserAgent = $( "{0} (PowerShell {1}; .NET CLR {2}; {3}; http://PoshCode.org)" -f $UserAgent, $(if($Host.Version){$Host.Version}else{"1.0"}), [Environment]::Version, [Environment]::OSVersion.ToString().Replace("Microsoft Windows ", "Win") ) $res = $req.GetResponse(); if($fileName -and !(Split-Path $fileName)) { $fileName = Join-Path (Convert-Path (Get-Location -PSProvider "FileSystem")) $fileName } elseif((!$Passthru -and ($fileName -eq $null)) -or (($fileName -ne $null) -and (Test-Path -PathType "Container" $fileName))) { [string]$fileName = ([regex]'(?i)filename=(.*)$').Match( $res.Headers["Content-Disposition"] ).Groups[1].Value $fileName = $fileName.trim("\/""'") $ofs = "" $fileName = [Regex]::Replace($fileName, "[$([Regex]::Escape(""$([System.IO.Path]::GetInvalidPathChars())$([IO.Path]::AltDirectorySeparatorChar)$([IO.Path]::DirectorySeparatorChar)""))]", "_") $ofs = " " if(!$fileName) { $fileName = $res.ResponseUri.Segments[-1] $fileName = $fileName.trim("\/") if(!$fileName) { $fileName = Read-Host "Please provide a file name" } $fileName = $fileName.trim("\/") if(!([IO.FileInfo]$fileName).Extension) { $fileName = $fileName + "." + $res.ContentType.Split(";")[0].Split("/")[1] } } $fileName = Join-Path (Convert-Path (Get-Location -PSProvider "FileSystem")) $fileName } if($Passthru) { $encoding = [System.Text.Encoding]::GetEncoding( $res.CharacterSet ) [string]$output = "" } if($res.StatusCode -eq 200) { [int]$goal = $res.ContentLength $reader = $res.GetResponseStream() if($fileName) { $writer = new-object System.IO.FileStream $fileName, "Create" } [byte[]]$buffer = new-object byte[] 4096 [int]$total = [int]$count = 0 do { $count = $reader.Read($buffer, 0, $buffer.Length); if($fileName) { $writer.Write($buffer, 0, $count); } if($Passthru) { $output += $encoding.GetString($buffer,0,$count) } elseif(!$quiet) { $total += $count if($goal -gt 0) { Write-Progress "Downloading $url" "Saving $total of $goal" -id 0 -percentComplete (($total/$goal)*100) } else { Write-Progress "Downloading $url" "Saving $total bytes..." -id 0 } } } while ($count -gt 0) $reader.Close() if($fileName) { $writer.Flush() $writer.Close() } if($Passthru){ $output } } $res.Close(); if( $fileName ) { $fileName } } ## Test-Signature - Returns true if the signature is valid OR is signed by: ## "4F8842037D878C1FCDC6FD1313B200449716C353" OR "7DEFA3C6C2138C05AAA135FB8096332DEB9603E1" function Test-Signature { PARAM ($ToTest) PROCESS { if($_) { $ToTest = $_ } if(!($ToTest -as [System.Management.Automation.Signature]) -and (Test-Path $ToTest -PathType Leaf)) { $ToTest = Get-AuthenticodeSignature $ToTest } if($ToTest -as [System.Management.Automation.Signature]) { $result = $false; #trap { continue } $result = ((($Signature.Status -eq "UnknownError") -and $Signature.SignerCertificate -and (($Signature.SignerCertificate.Thumbprint -eq "4F8842037D878C1FCDC6FD1313B200449716C353") -or ($Signature.SignerCertificate.Thumbprint -eq "7DEFA3C6C2138C05AAA135FB8096332DEB9603E1")) ) -or $Signature.Status -eq "Valid" ) return $result } else { return $false } } } # SIG # Begin signature block # MIILCQYJKoZIhvcNAQcCoIIK+jCCCvYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUrSuFdDwnWR3bARO1P1amiMU1 # E2agggbgMIIG3DCCBMSgAwIBAgIJALPpqDj9wp7xMA0GCSqGSIb3DQEBBQUAMIHj # MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hl # c3RlcjEhMB8GA1UEChMYaHR0cDovL0h1ZGRsZWRNYXNzZXMub3JnMSgwJgYDVQQL # Ex9TY3JpcHRpbmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MTcwNQYDVQQDEy5odHRw # Oi8vSHVkZGxlZE1hc3Nlcy5vcmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MScwJQYJ # KoZIhvcNAQkBFhhKYXlrdWxASHVkZGxlZE1hc3Nlcy5vcmcwHhcNMDkwMzE1MTkx # OTE5WhcNMTAwMzE1MTkxOTE5WjCBqzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5l # dyBZb3JrMRIwEAYDVQQHEwlSb2NoZXN0ZXIxITAfBgNVBAoTGGh0dHA6Ly9IdWRk # bGVkTWFzc2VzLm9yZzESMBAGA1UECxMJU2NyaXB0aW5nMRUwEwYDVQQDEwxKb2Vs # IEJlbm5ldHQxJzAlBgkqhkiG9w0BCQEWGEpheWt1bEBIdWRkbGVkTWFzc2VzLm9y # ZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPfqxOG9TQN+qZjZ6KfM # +zBK0YpjeyPL/cFgiGBhiIdYWTBtkbZydFr3IiERKRsUJ0/SKFbhf0C3Bvd/neTJ # qiZjH4D6xkrfdLlWMmmSXXqjSt48jZp+zfCAIaF8K84e9//7lMicdVFE6VcgoATZ # /eMKQky4JvphJpzDHYPLxLJQrKd0pjDDwspjdX5RedWkzeZBG7VfBnebLWUzgnMX # IxRQKfFCMryQDP8weceOnJjfJEf2FYmdpsEg5EKKKbuHsQCMVTxfteKdPvh1oh05 # 1GWyPsvEPh4auJUT8pAVvrdxq+/O9KW/UV01UxjRYM1vdklNw8g7mkJTrrHjSjl7 # tuugCnJjt5kN6v/OaUtRRMR68O85bSTVGOxJGCHUKlyuuTx9tnfIgy4siFYX1Ve8 # xwaAdN3haTon3UkWzncHOq3reCIVF0luwRZu7u+TnOAnz2BRlt+rcT0O73GN20Fx # gyN2f5VGBbw1KuS7T8XZ0TFCspUdgwAcmTGuEVJKGhVcGAvNlLx+KPc5dba4qEfs # VZ0MssC2rALC1z61qWuucb5psHYhuD2tw1SrztywuxihIirZD+1+yKE4LsjkM1zG # fQwDO/DQJwkdByjfB2I64p6mk36OlZAFxVfRBpXSCzdzbgKpuPsbtjkb5lGvKjE1 # JFVls1SHLJ9q80jHz6yW7juBAgMBAAGjgcgwgcUwHQYDVR0OBBYEFO0wLZyg+qGH # Z4WO8ucEGNIdU1T9MB8GA1UdIwQYMBaAFN2N42ZweJLF1mz0j70TMxePMcUHMAkG # A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgTwMCoGA1UdJQEB/wQgMB4GCCsGAQUF # BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMwCwYDVR0PBAQDAgTwMCwGCWCGSAGG+EIB # DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQUF # AAOCAgEAmKihxd6KYamLG0YLvs/unUTVJ+NW3jZP16R28PpmidY/kaBFOPhYyMl2 # bBGQABe7LA5rpHFAs0F56gYETNoFk0qREVvaoz9u18VfLb0Uwqtnq0P68L4c7p2q # V3nKmWjeI6H7BAyFuogxmMH5TGDfiqrrVSuh1LtPbkV2Wtto0SAxP0Ndyts2J8Ha # vu/2rt0Ic5AkyD+RblFPtzkCC/MLVwSNAiDSKGRPRrLaiGxntEzR59GRyf2vwhGg # oAXUqcJ/CVeHCP6qdSTM39Ut3RmMZHXz5qY8bvLgNYL6MtcJAx+EeUhW497alzm1 # jInXdbikIh0d/peTSDyLbjS8CPFFtS6Z56TDGMf+ouTpEA16otcWIPA8Zfjq+7n7 # iBHjeuy7ONoJ2VDNgqn9B+ft8UWRwnJbyB85T83OAGf4vyhCPz3Kg8kWxY30Bhnp # Fayc6zQKCpn5o5T0/a0BBHwAyMfr7Lhav+61GpzzG1KfAw58N2GV8KCPKNEd3Zdz # y07aJadroVkW5R+35mSafKRJp5pz20GDRwZQllqGH1Y/UJFEiI0Bme9ecbl2vzNp # JjHyl/jLVzNVrBI5Zwb0lCLsykApgNY0yrwEqaiqwcxq5nkXFDhDPQvbdulihSo0 # u33fJreCm2fFyGbTuvR61goSksAvLQhvijLAzcKqWKG+laOtYpAxggOTMIIDjwIB # ATCB8TCB4zELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMRIwEAYDVQQH # EwlSb2NoZXN0ZXIxITAfBgNVBAoTGGh0dHA6Ly9IdWRkbGVkTWFzc2VzLm9yZzEo # MCYGA1UECxMfU2NyaXB0aW5nIENlcnRpZmljYXRlIEF1dGhvcml0eTE3MDUGA1UE # AxMuaHR0cDovL0h1ZGRsZWRNYXNzZXMub3JnIENlcnRpZmljYXRlIEF1dGhvcml0 # eTEnMCUGCSqGSIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNzZXMub3JnAgkAs+mo # OP3CnvEwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJ # KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB # gjcCARUwIwYJKoZIhvcNAQkEMRYEFFB0prkrW1HtVAf2wTH5+DTkCsAhMA0GCSqG # SIb3DQEBAQUABIICABEAQKAyvqTfFFafUC385RpCcDhsjro+0j49prN/mnlS62p5 # z/UUGxk0jr6K0Un8ZizGBpS8G/9sENuZIZ+Bh9s7Jkf7rUnqosx0nYmAnBw/I40Q # a0s2OoYy1JWF+NeYQcJenG5zWOU2ezMBDf2nGolpxBMYbzmYEgmOZg+dpvJgLFEk # Vwxu5weA/Mc5TWDS7t91kHsBc+ePZHS4qCzpcH2g3sC2xzfpTyLkoEiAhodPn541 # JMc75dUBZwY0k2xDHfzTD1IzrtzJgX7KluA478yAU586hZOufGd3IHSnBA6pw4eE # IBC4shq7Ssj4UL4SL++sgkGIl62Re2LxSi1KUC21jLZFt1kG1grEe4PRTJ/V2cJZ # BUmG6pq06FjebOKGktrNaIp2KTMCL5aFAMN3CcXI4Uuh72glUhY9UtbqzpnSTxaw # zF9n0V2tqAqRhJOCrREELAjWq11HgKz7gYvTVRZ32UJ/VwGAurhwlHAhk+v+OUkd # WHrZ7JcRDrGMi9N+p1d1VZRrv0469C4UJm3sJNeuzfRAXrjQ64CiMu5aFf8etdZX # aeRV0fvJ6BgZk1myQZm759/ubaBP9B2G4ivsWyFCMhqcm4JsN260QT4hMbnABfub # RjojYa+nt085gUBDc508cd5Buw2/nR8qmlMB0RuCbw+xiRGf8Zvd566LouZn # SIG # End signature block