#Requires -version 1.0 ## PoshCode module v 3.2 ## 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.3 -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.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 = $(throw "You must specify a query string, or the id of the paste to get"), [string]$SaveAs, $url = $($PoshCode), [switch]$InBrowser, [switch]$Passthru, [switch]$Upgrade ) if($Upgrade) { Get-PoshCodeUpgrade } else { write-debug "Id: $id" if(!$id) { $results = @(([xml](Get-WebFile "$($url)api$($PoshCode.ApiVersion)/$($query)" -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.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 ) Write-Verbose "Downloading '$url'" $req = [System.Net.HttpWebRequest]::Create($url); $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) { Get-Item $fileName } } ## Test-Signature - Returns true if the signature is valid OR is signed by "F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5" 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 = ( $ToTest.Status -eq "Valid" -or (($ToTest.Status -eq "UnknownError") -and $ToTest.SignerCertificate -and ($ToTest.SignerCertificate.Thumbprint -eq "F05F583BB5EA4C90E3B9BF1BDD0B657701245BD5") )) return $result } else { return $false } } } # SIG # Begin signature block # MIIK0AYJKoZIhvcNAQcCoIIKwTCCCr0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU/38TVYpMWC0NW6iorOpd6S2T # F++gggbEMIIGwDCCBKigAwIBAgIJAKpDRVMtv0LqMA0GCSqGSIb3DQEBBQUAMIHG # MQswCQYDVQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hl # c3RlcjEaMBgGA1UEChMRSHVkZGxlZE1hc3Nlcy5vcmcxHjAcBgNVBAsTFUNlcnRp # ZmljYXRlIEF1dGhvcml0eTErMCkGA1UEAxMiSm9lbCBCZW5uZXR0IENlcnRpZmlj # YXRlIEF1dGhvcml0eTEnMCUGCSqGSIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNz # ZXMub3JnMB4XDTA4MDcwMjAzNTA1OVoXDTA5MDcwMjAzNTA1OVowgcAxCzAJBgNV # BAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazESMBAGA1UEBxMJUm9jaGVzdGVyMRow # GAYDVQQKExFIdWRkbGVkTWFzc2VzLm9yZzEuMCwGA1UECxMlaHR0cDovL0h1ZGRs # ZWRNYXNzZXMub3JnL0NvZGVDZXJ0LmNydDEVMBMGA1UEAxMMSm9lbCBCZW5uZXR0 # MScwJQYJKoZIhvcNAQkBFhhKYXlrdWxASHVkZGxlZE1hc3Nlcy5vcmcwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXuceXJZYARJbSTU4hoh91goVp2POx # 6Mz/QZ6D5jcT/JNhdW2GwYQ9YUxNj8jkhXg2Ixbgb1djRGMFC/ekgRkgLxyiuhRh # NrVE1IdV4hT4as3idqnvWOi0S3z2R2EGdebqwm2mrRmq9+DbY+FGxuNwLboWZx8Z # roGlLLHRPzt9pabQq/Nu/FIFO+4JzZ8S5ZnEaKTm4dpD0g6j653OWYVvNXJbS/W4 # Dis5aRkHT1q1Gp02dYHh3NTKrpv1nus9BTDlJRwmU/FgGLNQIvnRwqVoBh+I7tVq # NIRnI1RpDTGyFEohbH8mRlwq3z4ijtb6j9boUJEqd8hQshzUMcALoTIR1tN/5APX # u2j4OqGFESM/OG0i2hLKbnP81u581aZT1BfVfQxvDuWrFiurMxllVGY1NvKkXwc8 # aOZktqMQWbWAs2bxZqERbOILXOmkL/mvPdy+e5yQveriHAhrDONu7a79ylreMHBR # XrmYJTK2G/aHvB5vrXjMPw0TBeph0sM2BN2eVzenAAMsIiGlXPXvtKrpKRiBdx5f # 9SV5dyUG2tR8ANDuc2AMB8FKICuMUd8Sx96p4FOBQhXhvF/RZcWZIW5o+A4sHvYE # /s4oiX7LxGrQK2abNiCVs9BDLI/EcSs/TP+ZskBqu7Qb+AVeevoY3T7skihuyC/l # h7EwqjfNpVQ9UwIDAQABo4G0MIGxMB0GA1UdDgQWBBTgB9XYJV/kJAvnkWmKDHsh # 7Cn3PzAfBgNVHSMEGDAWgBQ+5x4ah0JG0o4iUj0TebNd4MCVxTAJBgNVHRMEAjAA # MBEGCWCGSAGG+EIBAQQEAwIEEDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzALBgNV # HQ8EBAMCBsAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp # ZmljYXRlMA0GCSqGSIb3DQEBBQUAA4ICAQAw8B6+s48CZZo5h5tUeKV7OWNXKRG7 # xkyavMkXpEi58BSLutmE3O7smc3uvu3TdCXENNUlGrcq/KQ8y2eEI8QkHgT99VgX # r+v5xu2KnJXiOOIxi65EZybRFFFaGJNodTcrK8L/tY6QLF02ilOlEgfcc1sV/Sj/ # r60JS1iXIMth7nYZVjtWeYXOrsd+I+XwJuoVNJlELNdApOU4ZVNrPEuV+QRNMimj # lqIOv2tn9TDdNGUqaOCI0w+a1XQvapEPWETfQK+o9pvYINTswGDjNeb7Xz8ar2JB # 9IVs2xtxDohHB75kyRrlY1hkoY5j12ZhWOlm0L9Ks6XvmMtXJIjj0/m9Z+3s+9p6 # U7IYjz5NnzmDvtNUn2y9zxB/rUx/JqoUO3BWRKiLX0lvGRWJlzFr9978kH2SXxAD # rsKfzB7YZzMh9hZkGNlJf4T+HTB/OXG1jyfkyqQvhNB/tDAaq+ejDtKNBF4hMS7K # Z0B4vagIxFwMuTiei4UaOjrGzeCfT9w1Bmj6uLJme5ydQVM0V7z3Z6jR3LVq4c4s # Y1dfPmYlw62cbyV9Kb/H2hYw5K0OMX60LfLQZOzIPzAeRJ87NufwZnC1afxsSCmU # bvSx4kCMgRZMXw+d1SHRhh7z+06YTQjnUMmtTGt7DtUkU6I8LKEWF/mAzF7sq/7P # AyhPsbu91X5FuzGCA3YwggNyAgEBMIHUMIHGMQswCQYDVQQGEwJVUzERMA8GA1UE # CBMITmV3IFlvcmsxEjAQBgNVBAcTCVJvY2hlc3RlcjEaMBgGA1UEChMRSHVkZGxl # ZE1hc3Nlcy5vcmcxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTErMCkG # A1UEAxMiSm9lbCBCZW5uZXR0IENlcnRpZmljYXRlIEF1dGhvcml0eTEnMCUGCSqG # SIb3DQEJARYYSmF5a3VsQEh1ZGRsZWRNYXNzZXMub3JnAgkAqkNFUy2/QuowCQYF # Kw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkD # MQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJ # KoZIhvcNAQkEMRYEFKyiygczc6ZrBcO3k6wX+EqZmrXqMA0GCSqGSIb3DQEBAQUA # BIICAD9rTVjFRY2wAdClId376h5scLuP4PA343Chc21BlFwlcvQ7D9BzetyALX5B # vp3cHexVzra+9NR6jdZoKCqH5bYUgvPeWbo6oYmeMV0cgnMz1AgKHK8erYSB2swX # wwlxyFJd9+2LMoqSkhWyKPHn0jj880g1vZYn2HeupdNqkOJMMPXuG8uYTauNBf+8 # gSoIogrFGMSVqDthN6xWopPiHygp8SC/nBrvFIf68sFDdoBzYA07mK3k3xB3QKIF # eGGDYe9d8ZtsSGV23N4PMUqm68wINNBiEN7DACT6tSAa4Rt5oetA0bMdslIQM8rK # PxmHTA8GGaTOzjgWpUeeBm5zUt7PaIE+Iz44RPOehsjdyBUeHC8AHngsWF/kN9De # 6O6Ycc997+RBIDqM+1tDtAkqhAx2nqMMXa6/153qAL3S3S25nzgOxuIRt/jC3xlQ # J9RsmTSbDfkTd0gCFzgdDx1Fp5kF3Sj4etipsqeA46zRNfjHY/NvgnzCt/L0s3QD # 7NlDfzOkkzaQnaVAF9bMvVB/KHWrNIedPBRMOQkNobOL7nJvVGsI57V0RC9z5fyd # xXfjlQtp0rKTNI8rURFjOkUoBXoazv7Di1/QIUF+sjFQhnPATnBWzDm+TXLuaW9M # LidZnr//JnPPMQIJJ6fF2OCIhdgBLnihmDtolhICqa9Mc3wu # SIG # End signature block