├── output └── output.txt ├── downloads └── downloads.txt ├── README.md ├── scripts ├── Ccleaner.ps1 ├── Chrome.ps1 ├── Skype.ps1 ├── FireFox.ps1 ├── template.ps1 └── Java.ps1 └── download.ps1 /output/output.txt: -------------------------------------------------------------------------------- 1 | Script output will go here! -------------------------------------------------------------------------------- /downloads/downloads.txt: -------------------------------------------------------------------------------- 1 | Default download directory -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # psNinjaDownloader # 2 | Modular PowerShell File Downloading Utility 3 | 4 | See this blog post for details on how to use it! 5 | 6 | http://www.gngrninja.com/script-ninja/2017/3/10/powershell-ninjadownloader-modular-file-download-utility 7 | 8 | You can also use the following command to get started: 9 | Get-Help .\download.ps1 -Full 10 | 11 | # Examples # 12 | 13 | ## Example 1 ## 14 | 15 | PS .\download.ps1 -DownloadName all -OutputType all 16 | 17 | 1. All scripts in %scriptDir%\scripts executed 18 | 2. Files downloaded to %scriptDir%\downloads 19 | 3. Results exported to %scriptDir%\output as HTML, XML, and CSV 20 | 21 | ## Example 2 ## 22 | 23 | PS .\download.ps1 -DownloadName all -OutputType all -DownloadFolder C:\temp\downloads 24 | 25 | 1. All scripts in %scriptDir%\scripts executed 26 | 2. Files downloaded to C:\temp\downloads (created if it does not exist) 27 | 3. Results exported to %scriptDir%\output as HTML, XML, and CSV 28 | 29 | ## Example 3 ## 30 | 31 | PS .\download.ps1 -DownloadName Chrome -OutputType html 32 | 33 | 1. Script %scriptDir%\scripts\Chrome.ps1 executed 34 | 2. File downloaded to %scriptDir%\downloads 35 | 3. Results exported to %scriptDir%\output as HTML -------------------------------------------------------------------------------- /scripts/Ccleaner.ps1: -------------------------------------------------------------------------------- 1 | #Script setup 2 | $navUrl = 'http://www.piriform.com/ccleaner/download/portable/downloadfile' 3 | 4 | $downloadInfo = [PSCustomObject]@{ 5 | 6 | DownloadName = '' 7 | Content = '' 8 | Success = $false 9 | Error = '' 10 | 11 | } 12 | 13 | #Go to first page 14 | Try { 15 | 16 | $downloadRequest = Invoke-WebRequest -Uri $navURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 17 | 18 | } 19 | Catch { 20 | 21 | $errorMessage = $_.Exception.Message 22 | 23 | $downloadInfo.Error = $errorMessage 24 | 25 | return $downloadInfo 26 | 27 | } 28 | 29 | #Get file info 30 | $downloadFile = $downloadRequest.Headers.Location 31 | 32 | #Parse file name 33 | Switch ($downloadRequest.BaseResponse.ContentType) { 34 | 35 | 'unknown/unknown' { 36 | 37 | $downloadInfo.DownloadName = $downloadRequest.Headers.'content-disposition'.Split('=')[1] 38 | $downloadInfo.Content = $downloadRequest.Content 39 | $downloadInfo.Success = $true 40 | 41 | return $downloadInfo 42 | 43 | } 44 | 45 | Default { 46 | 47 | $downloadInfo.Error = "Content type [$($downloadRequest.BaseResponse.ContentType)] not handled!" 48 | 49 | return $downloadInfo 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /scripts/Chrome.ps1: -------------------------------------------------------------------------------- 1 | #Script setup 2 | $navUrl = 'https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7B96F81EF0-C92E-71F2-6061-14395891B357%7D%26lang%3Den%26browser%3D4%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dprefers%26ap%3Dx64-stable-statsdef_1%26installdataindex%3Ddefaultbrowser/update2/installers/ChromeSetup.exe' 3 | 4 | $downloadInfo = [PSCustomObject]@{ 5 | 6 | DownloadName = '' 7 | Content = '' 8 | Success = $false 9 | Error = '' 10 | 11 | } 12 | 13 | #Go to first page 14 | Try { 15 | 16 | $downloadRequest = Invoke-WebRequest -Uri $navURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 17 | 18 | } 19 | Catch { 20 | 21 | $errorMessage = $_.Exception.Message 22 | 23 | $downloadInfo.Error = $errorMessage 24 | 25 | return $downloadInfo 26 | 27 | } 28 | 29 | #Get file info 30 | $downloadFile = $downloadRequest.Headers.Location 31 | 32 | #Parse file name 33 | Switch ($downloadRequest.BaseResponse.ContentType) { 34 | 35 | 'application/octet-stream' { 36 | 37 | $downloadInfo.DownloadName = 'Chrome.exe' 38 | $downloadInfo.Content = $downloadRequest.Content 39 | $downloadInfo.Success = $true 40 | 41 | return $downloadInfo 42 | 43 | } 44 | 45 | Default { 46 | 47 | $downloadInfo.Error = "Content type [$($downloadRequest.BaseResponse.ContentType)] not handled!" 48 | 49 | return $downloadInfo 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /scripts/Skype.ps1: -------------------------------------------------------------------------------- 1 | #Script setup 2 | $navUrl = 'https://get.skype.com/go/getskype-full' 3 | $downloadInfo = [PSCustomObject]@{ 4 | 5 | DownloadName = '' 6 | Content = '' 7 | Success = $false 8 | Error = '' 9 | 10 | } 11 | 12 | #Go to first page 13 | Try { 14 | 15 | $downloadRequest = Invoke-WebRequest -Uri $navURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 16 | 17 | } 18 | Catch { 19 | 20 | $errorMessage = $_.Exception.Message 21 | 22 | $downloadInfo.Error = $errorMessage 23 | 24 | return $downloadInfo 25 | 26 | } 27 | 28 | 29 | if ($downloadRequest.Headers.Location -match '.+\.exe') { 30 | 31 | $downloadURL = $downloadRequest.Headers.Location 32 | 33 | } else { 34 | 35 | $downloadInfo.Error = "Unable to find exe in header information." 36 | 37 | return $downloadInfo 38 | 39 | } 40 | 41 | #Get file info 42 | $downloadFile = $downloadRequest.Headers.Location 43 | 44 | #Parse file name 45 | if ($downloadRequest.Headers.Location) { 46 | 47 | $downloadInfo.DownloadName = $downloadFile.SubString($downloadFile.LastIndexOf('/')+1).Replace('%20',' ') 48 | 49 | } 50 | 51 | Switch ($downloadRequest.StatusDescription) { 52 | 53 | 'Found' { 54 | 55 | #Write-Host "Status Description is [Found], downloading from redirect URL [$($downloadRequest.Headers.Location)]."`n 56 | $downloadRequest = Invoke-WebRequest -Uri $downloadRequest.Headers.Location -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 57 | 58 | } 59 | 60 | default { 61 | 62 | $downloadInfo.Error = "Status description [$($downloadRequest.StatusDescription)] not handled!" 63 | 64 | return $downloadInfo 65 | 66 | } 67 | 68 | } 69 | 70 | Switch ($downloadRequest.BaseResponse.ContentType) { 71 | 72 | 'application/x-msdownload' { 73 | 74 | $downloadInfo.Content = $downloadRequest.Content 75 | $downloadInfo.Success = $true 76 | 77 | return $downloadInfo 78 | 79 | } 80 | 81 | Default { 82 | 83 | $downloadInfo.Error = "Content type [$($downloadRequest.BaseResponse.ContentType)] not handled!" 84 | 85 | return $downloadInfo 86 | 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /scripts/FireFox.ps1: -------------------------------------------------------------------------------- 1 | #Script setup 2 | $navUrl = 'https://www.mozilla.org/en-US/firefox/all/' 3 | $matchText = '.+windows.+64.+English.+\(US\)' 4 | $downloadInfo = [PSCustomObject]@{ 5 | 6 | DownloadName = '' 7 | Content = '' 8 | Success = $false 9 | Error = '' 10 | 11 | } 12 | 13 | #Go to first page 14 | 15 | Try { 16 | 17 | $downloadRequest = Invoke-WebRequest -Uri $navURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 18 | 19 | } 20 | Catch { 21 | 22 | $errorMessage = $_.Exception.Message 23 | 24 | $downloadInfo.Error = $errorMessage 25 | 26 | return $downloadInfo 27 | 28 | } 29 | 30 | #Look for urls that match 31 | $downloadURL = $downloadRequest.Links | Where-Object {$_.Title -Match $matchText} | Select-Object -ExpandProperty href 32 | 33 | #Go to matching URL, look for download file (keeping redirects at 0) 34 | try { 35 | 36 | $downloadRequest = Invoke-WebRequest -Uri $downloadURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 37 | 38 | } 39 | catch { 40 | 41 | $errorMessage = $_.Exception.Message 42 | 43 | $downloadInfo.Error = $errorMessage 44 | 45 | return $downloadInfo 46 | 47 | } 48 | 49 | #Get file info 50 | $downloadFile = $downloadRequest.Headers.Location 51 | 52 | #Parse file name 53 | if ($downloadRequest.Headers.Location) { 54 | 55 | $downloadInfo.DownloadName = $downloadFile.SubString($downloadFile.LastIndexOf('/')+1).Replace('%20',' ') 56 | 57 | } 58 | 59 | Switch ($downloadRequest.StatusDescription) { 60 | 61 | 'Found' { 62 | 63 | $downloadRequest = Invoke-WebRequest -Uri $downloadRequest.Headers.Location -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 64 | 65 | } 66 | 67 | default { 68 | 69 | $downloadInfo.Error = "Status description [$($downloadRequest.StatusDescription)] not handled!" 70 | 71 | return $downloadInfo 72 | 73 | } 74 | 75 | } 76 | 77 | #Switch out the proper content type for the file download 78 | Switch ($downloadRequest.BaseResponse.ContentType) { 79 | 80 | 'application/x-msdos-program' { 81 | 82 | $downloadInfo.Content = $downloadRequest.Content 83 | $downloadInfo.Success = $true 84 | 85 | return $downloadInfo 86 | 87 | } 88 | 89 | Default { 90 | 91 | $downloadInfo.Error = "Content type [$($downloadRequest.BaseResponse.ContentType)] not handled!" 92 | 93 | return $downloadInfo 94 | 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /scripts/template.ps1: -------------------------------------------------------------------------------- 1 | #Template example (works for Firefox, adjust as needed for your download) 2 | 3 | #Set this to the URL you'll be navigating to first 4 | $navUrl = 'https://www.mozilla.org/en-US/firefox/all/' 5 | 6 | #Text to match on, if applicable 7 | $matchText = '.+windows.+64.+English.+\(US\)' 8 | 9 | # IMPORTANT: This is the format of the object needed to be returned to the description 10 | # Whichever way you get the information, you need to return an object with the following properties: 11 | # DownloadName (string, file name) 12 | # Content (byte array, file contents) 13 | # Success (boolean) 14 | # Error (string, any error received) 15 | $downloadInfo = [PSCustomObject]@{ 16 | 17 | DownloadName = '' 18 | Content = '' 19 | Success = $false 20 | Error = '' 21 | 22 | } 23 | 24 | #Go to first page 25 | Try { 26 | 27 | $downloadRequest = Invoke-WebRequest -Uri $navURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 28 | 29 | } 30 | Catch { 31 | 32 | $errorMessage = $_.Exception.Message 33 | 34 | $downloadInfo.Error = $errorMessage 35 | 36 | return $downloadInfo 37 | 38 | } 39 | 40 | #Look for urls that match 41 | $downloadURL = $downloadRequest.Links | Where-Object {$_.Title -Match $matchText} | Select-Object -ExpandProperty href 42 | 43 | #Go to matching URL, look for download file (keeping redirects at 0) 44 | try { 45 | 46 | $downloadRequest = Invoke-WebRequest -Uri $downloadURL -MaximumRedirection 0 -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -ErrorAction SilentlyContinue 47 | 48 | } 49 | catch { 50 | 51 | $errorMessage = $_.Exception.Message 52 | 53 | $downloadInfo.Error = $errorMessage 54 | 55 | return $downloadInfo 56 | 57 | } 58 | 59 | #Get file info 60 | $downloadFile = $downloadRequest.Headers.Location 61 | 62 | #Parse file name, whichever way needed 63 | if ($downloadRequest.Headers.Location) { 64 | 65 | $downloadInfo.DownloadName = $downloadFile.SubString($downloadFile.LastIndexOf('/')+1).Replace('%20',' ') 66 | 67 | } 68 | 69 | #Switch out the StatusDescription, as applicable 70 | Switch ($downloadRequest.StatusDescription) { 71 | 72 | 'Found' { 73 | 74 | $downloadRequest = Invoke-WebRequest -Uri $downloadRequest.Headers.Location -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox 75 | 76 | } 77 | 78 | default { 79 | 80 | $downloadInfo.Error = "Status description [$($downloadRequest.StatusDescription)] not handled!" 81 | 82 | return $downloadInfo 83 | 84 | } 85 | 86 | } 87 | 88 | #Switch out the proper content type for the file download 89 | Switch ($downloadRequest.BaseResponse.ContentType) { 90 | 91 | 'application/x-msdos-program' { 92 | 93 | $downloadInfo.Content = $downloadRequest.Content 94 | $downloadInfo.Success = $true 95 | 96 | return $downloadInfo 97 | 98 | } 99 | 100 | Default { 101 | 102 | $downloadInfo.Error = "Content type [$($downloadRequest.BaseResponse.ContentType)] not handled!" 103 | 104 | return $downloadInfo 105 | 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /scripts/Java.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-IEWait { #Begin function Invoke-IEWait 2 | [cmdletbinding()] 3 | Param( 4 | [Parameter( 5 | Mandatory, 6 | ValueFromPipeLine 7 | )] 8 | $ieObject 9 | ) 10 | 11 | While ($ieObject.Busy) { 12 | 13 | Start-Sleep -Milliseconds 10 14 | 15 | } 16 | 17 | } #End function Invoke-IEWait 18 | 19 | function Invoke-IECleanUp { #Begin function Invoke-IECleanUp 20 | [cmdletbinding()] 21 | param( 22 | [Parameter( 23 | Mandatory, 24 | ValueFromPipeLine 25 | )] 26 | $ieObject 27 | ) 28 | 29 | #Wait for logout 30 | $ieObject | Invoke-IEWait 31 | 32 | #Clean up IE Object 33 | $ieObject.Quit() 34 | 35 | #Release COM Object 36 | [void][Runtime.Interopservices.Marshal]::ReleaseComObject($ieObject) 37 | 38 | } #End function Invoke-IECleanUp 39 | 40 | $downloadInfo = [PSCustomObject]@{ 41 | 42 | DownloadName = '' 43 | Content = '' 44 | Success = $false 45 | Error = '' 46 | 47 | } 48 | 49 | Try { 50 | 51 | #Instantiate new IE Object 52 | $ieObject = New-Object -comobject "InternetExplorer.Application" 53 | 54 | #Navigate to download list where we have to accept 55 | $ieObject.Navigate("http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html") 56 | 57 | #Important! Wait for page to load 58 | $ieObject | Invoke-IEWait 59 | 60 | #Click the accept radio button 61 | ($ieObject.Document.IHTMLDocument3_getElementsByTagName('input') | Where-Object {$_.Name -eq 'agreementjre-8u121-oth-JPR' -and $_.Status -eq $false}).Click() 62 | 63 | #Wait for page to load 64 | $ieObject | Invoke-IEWait 65 | 66 | #Get the download URL now that we can see it 67 | $downloadUrl = $ieObject.Document.links | Where-Object {$_.href -match '^http://download\.oracle\.com.+windows\-x64\.exe$'} | Select-Object -expandProperty Href 68 | 69 | #Get just the file name from the downloadUrl 70 | $shortFileName = $downloadUrl.Substring($downloadUrl.LastIndexOf('/')+1) 71 | $downloadInfo.DownloadName = $shortFileName 72 | 73 | #Close and clean up the IE Object, we no longer need it 74 | $ieObject | Invoke-IECleanUp 75 | 76 | #Create the cookie that says we accepted the agreement 77 | $cookie = New-Object System.Net.Cookie 78 | $cookie.Name = "oraclelicense" 79 | $cookie.Value = "accept-securebackup-cookie" 80 | $cookie.Domain = 'oracle.com' 81 | 82 | #Create web session, and add the cookie we created to it 83 | $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession 84 | 85 | $session.Cookies.Add($cookie) 86 | 87 | #Use Invoke-WebRequest with the session we created (that has the cookie), and the download URL 88 | $getFile = Invoke-WebRequest -Uri $downloadUrl -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer -ErrorAction SilentlyContinue -WebSession $session 89 | $downloadInfo.Content = $getFile.Content 90 | $downloadInfo.Success = $true 91 | 92 | return $downloadInfo 93 | 94 | } 95 | Catch { 96 | 97 | $errorMessage = $_.Exception.Message 98 | $downloadInfo.Error = $errorMessage 99 | 100 | return $downloadInfo 101 | 102 | } -------------------------------------------------------------------------------- /download.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script downloads specific tools and programs from the internet based on scripts located in %scriptDir%\scripts. 4 | .DESCRIPTION 5 | To use this script, execute it with the parameters set for the download you'd like to get. If you do not specify a folder, it will default to %scriptDir%\downloads 6 | Download scripts are stored in %scriptDir%\scripts 7 | 8 | The parameter downloadName must match a script name in the %scriptDir%\scripts folder (omitting .ps1). 9 | Specify 'all' to execute all the .ps1 files in %scriptDir%\scripts, minus template.ps1 10 | 11 | You can create your own script, just be sure to return the following object from it: 12 | 13 | $downloadInfo = [PSCustomObject]@{ 14 | 15 | DownloadName = '' 16 | Content = '' 17 | Success = $false 18 | Error = '' 19 | 20 | } 21 | 22 | IMPORTANT: This is the format of the object needed to be returned to the description 23 | Whichever way you get the information, you need to return an object with the following properties: 24 | DownloadName (string, file name) 25 | Content (byte array, file contents) 26 | Success (boolean) 27 | Error (string, any error received) 28 | .PARAMETER DownloadName 29 | Argument: This is the name of the script you'd like to execute (use 'all' to execute all scripts) 30 | Scripts located in %scriptDir%\scripts 31 | .PARAMETER OutputType 32 | Argument: This parameter affects the type of text you'd like to display. 33 | 34 | Valid types: 35 | XML 36 | CSV (default) 37 | HTML 38 | All 39 | 40 | Results exported to %scriptDir%\output 41 | .PARAMETER DownloadFolder 42 | Argument: The path you'd like to download the files to. 43 | 44 | Will use %scriptDir%\output if nothing is specified. 45 | If the directory does not exist, it will be created. 46 | .PARAMETER UnZip 47 | Argument: This is a switch, flag if you want to use it 48 | 49 | This switch will look for any files that are zip files, and unzip them. 50 | The contents will go to a folder created in the downloads folder, which will 51 | have the name of the file downloaded. 52 | .PARAMETER ListOnly 53 | Returns a list of possible names and their script paths 54 | .NOTES 55 | Name: download.ps1 56 | Author: Mike Roberts aka Ginger Ninja 57 | DateCreated: 3/10/2017 58 | .EXAMPLE 59 | .\download.ps1 60 | (or) 61 | .\download.ps1 -listOnly:$true 62 | 63 | Returns a list of possible names and their script paths 64 | .EXAMPLE 65 | .\download.ps1 -DownloadName Chrome -OutputType html 66 | --------------------------------------------------------------- 67 | 68 | 1. Script %scriptDir%\scripts\Chrome.ps1 executed 69 | 2. File downloaded to %scriptDir%\downloads 70 | 3. Results exported to %scriptDir%\output as HTML 71 | 72 | .EXAMPLE 73 | .\download.ps1 -DownloadName all -OutputType all 74 | --------------------------------------------------------------- 75 | 76 | 1. All scripts in %scriptDir%\scripts executed 77 | 2. Files downloaded to %scriptDir%\downloads 78 | 3. Results exported to %scriptDir%\output as HTML, XML, and CSV 79 | .EXAMPLE 80 | .\download.ps1 -DownloadName all -OutputType all -DownloadFolder C:\temp\downloads 81 | --------------------------------------------------------------- 82 | 83 | 1. All scripts in %scriptDir%\scripts executed 84 | 2. Files downloaded to C:\temp\downloads (created if it does not exist) 85 | 3. Results exported to %scriptDir%\output as HTML, XML, and CSV 86 | .OUTPUTS 87 | A custom object is output that contains the following: 88 | ScriptName (string, name of file) 89 | Success (boolean, true if file was downloaded) 90 | Error (string, any errors) 91 | FileInfo (A custom object itself with file information) 92 | FileName (string, the file name) 93 | LocalPath (string, full path of file) 94 | Error (string, any errors) 95 | VerifiedToExist (boolean, true if file exists) 96 | ExtractionResults (A custom object that exists if a zip was extracted) 97 | ExtractedTo (string, path contents were extracted to) 98 | ExtractionSuccess (boolean, status of extraction) 99 | Error (string, error message if any during extraction) 100 | .LINK 101 | http://www.gngrninja.com/script-ninja/2017/3/10/powershell-ninjadownloader-modular-file-download-utility 102 | #> 103 | #Requires -Version 3.0 104 | [cmdletbinding()] 105 | param( 106 | [Parameter( 107 | Mandatory = $true, 108 | ParameterSetName='downloads' 109 | )] 110 | [String] 111 | $DownloadName, 112 | [Parameter( 113 | Mandatory = $false, 114 | ParameterSetName='downloads' 115 | )] 116 | [ValidateSet('html','csv','xml','all')] 117 | [String] 118 | $OutputType = 'csv', 119 | [Parameter( 120 | Mandatory = $false, 121 | ParameterSetName='downloads' 122 | )] 123 | [String] 124 | $DownloadFolder, 125 | [Parameter( 126 | Mandatory = $false, 127 | ParameterSetName='downloads' 128 | )] 129 | [Switch] 130 | $UnZip, 131 | [Parameter( 132 | Mandatory = $false, 133 | ParameterSetName='listOnly' 134 | )] 135 | [Switch] 136 | $ListOnly 137 | ) 138 | 139 | #Script setup 140 | #Get the path of the script folder and then set the path to the scripts 141 | $scriptFolder = Split-Path -Parent $MyInvocation.MyCommand.Path 142 | $pathToScripts = "$scriptFolder\scripts" 143 | $outputDir = "$scriptFolder\output" 144 | 145 | #Check to see if $list is true 146 | if ($ListOnly -or [String]::IsNullOrEmpty($DownloadName)) { 147 | 148 | $scriptList = Get-ChildItem -Path $pathToScripts | Where-Object {$_.Extension -eq '.ps1' -and $_.Name -notmatch '^template'} 149 | 150 | [System.Collections.ArrayList]$availableScripts = @() 151 | 152 | ForEach ($file in $scriptList) { 153 | 154 | $script = [PSCustomObject]@{ 155 | 156 | Name = $file | Select-Object -ExpandProperty Name | ForEach-Object {$_.TrimEnd('.ps1')} 157 | ScriptPath = $file.FullName 158 | 159 | } 160 | 161 | $availableScripts.Add($script) | Out-Null 162 | 163 | } 164 | 165 | Return $availableScripts 166 | 167 | } 168 | 169 | #If $downloadFolder is not specified, attempt to set it to scriptFolder\downloads (and creat if it doesn't exist) 170 | if ([String]::IsNullOrEmpty($DownloadFolder)) { #Begin if for downloadFolder not being specified 171 | 172 | if (Test-Path -Path "$scriptFolder\downloads") { 173 | 174 | $DownloadFolder = "$scriptFolder\downloads" 175 | 176 | Write-Verbose "No download folder specified, using [$DownloadFolder]" 177 | 178 | } else { 179 | 180 | Write-Verbose "Download folder doesn't exist in [$scriptFolder], attempting to create!" 181 | 182 | Try { 183 | 184 | New-Item -ItemType Directory -Path "$scriptFolder\downloads" 185 | 186 | $DownloadFolder = "$scriptFolder\downloads" 187 | 188 | Write-Verbose "Download folder [$DownloadFolder] created!" 189 | 190 | 191 | } 192 | Catch { 193 | 194 | $errorMessage = $_.Exception.Message 195 | 196 | Write-Error "Error creating folder [$errorMessage], exiting!" 197 | 198 | Break 199 | 200 | } 201 | 202 | } 203 | 204 | } else { #End if/begin else for downloadFolder not being specified 205 | 206 | if (Test-Path -Path $DownloadFolder) { 207 | 208 | Write-Verbose "Folder accessible! Using [$DownloadFolder]" 209 | 210 | } else { 211 | 212 | Write-Verbose "Download folder doesn't exist [$DownloadFolder], attempting to create!" 213 | 214 | Try { 215 | 216 | New-Item -ItemType Directory -Path $DownloadFolder 217 | 218 | Write-Verbose "Download folder [$DownloadFolder] created!" 219 | 220 | 221 | } 222 | Catch { 223 | 224 | $errorMessage = $_.Exception.Message 225 | 226 | Write-Error "Error creating folder [$errorMessage], exiting!" 227 | 228 | Break 229 | 230 | } 231 | 232 | } 233 | 234 | } #End if for downloadFolder 235 | 236 | if (!(Test-Path -Path $outputDir)) { 237 | 238 | Write-Verbose "Creating output folder as it does not exist! [$scriptFolder\output]" 239 | 240 | New-Item -ItemType Directory -Path $outputDir 241 | 242 | } 243 | 244 | #Empty array for our results, later 245 | [System.Collections.ArrayList]$resultsArray = @() 246 | 247 | function Invoke-FileWrite { #Begin function Invoke-FileWrite 248 | [cmdletbinding()] 249 | param( 250 | [Parameter(Mandatory)] 251 | $Content, 252 | [Parameter(Mandatory)] 253 | [String] 254 | $LocalFolder, 255 | [Parameter(Mandatory)] 256 | [string] 257 | $FileName 258 | ) 259 | 260 | if (Test-Path $localFolder -ErrorAction SilentlyContinue) { 261 | 262 | $localFullPath = "$LocalFolder\$FileName" 263 | 264 | [io.file]::WriteAllBytes($localFullPath,$Content) 265 | 266 | if (Test-Path $localFullPath -ErrorAction SilentlyContinue) { 267 | 268 | $returnObject = [PSCustomObject]@{ 269 | 270 | FileName = $fileName 271 | LocalPath = $localFullPath 272 | Error = '' 273 | VerifiedToExist = $true 274 | 275 | } 276 | 277 | } 278 | 279 | else { 280 | 281 | $returnObject = [PSCustomObject]@{ 282 | 283 | FileName = $FileName 284 | LocalPath = $localFullPath 285 | Error = '' 286 | VerifiedToExist = $false 287 | 288 | } 289 | 290 | } 291 | 292 | return $returnObject 293 | 294 | } 295 | 296 | else { 297 | 298 | $returnObject = [PSCustomObject]@{ 299 | 300 | FileName = $FileName 301 | LocalPath = $localFullPath 302 | Error = "Invoke-FileWrite -> Folder [$LocalFolder] inaccessible!" 303 | VerifiedToExist = $false 304 | 305 | } 306 | 307 | return $returnObject 308 | 309 | } 310 | 311 | } #End function Invoke-FileWrite 312 | 313 | function Invoke-FileCheck { #Begin function Invoke-FileCheck 314 | [cmdletbinding()] 315 | param( 316 | [Parameter(Mandatory)] 317 | [String] 318 | $DownloadName 319 | ) 320 | 321 | if ($DownloadName -eq 'all') { 322 | 323 | [System.Collections.ArrayList]$scriptInfo = @() 324 | 325 | $scriptList = Get-ChildItem -Path $pathToScripts | Where-Object {$_.Extension -eq '.ps1' -and $_.Name -notmatch '^template'} 326 | 327 | foreach ($script in $scriptList) { 328 | 329 | $scriptObject = $null 330 | 331 | $scriptObject = [PSCustomObject]@{ 332 | 333 | ScriptName = $script.Name 334 | ScriptPath = $script.FullName 335 | ScriptExists = $true 336 | 337 | } 338 | 339 | $scriptInfo.Add($scriptObject) | Out-Null 340 | 341 | } 342 | 343 | } else { 344 | 345 | $scriptInfo = [PSCustomObject]@{ 346 | 347 | ScriptName = "$DownloadName.ps1" 348 | ScriptPath = "$pathToScripts\$DownloadName.ps1" 349 | ScriptExists = $false 350 | 351 | } 352 | 353 | Write-Verbose "Checking for script that matches [$DownloadName]!" 354 | 355 | If (Test-Path -Path $scriptInfo.ScriptPath) { 356 | 357 | $scriptInfo.ScriptExists = $true 358 | 359 | } 360 | 361 | } 362 | 363 | Return $scriptInfo 364 | 365 | } #End function Invoke-FileCheck 366 | 367 | function Invoke-CsvFormat { #Begin function Invoke-CsvFormat 368 | [cmdletbinding()] 369 | param( 370 | [Parameter( 371 | Mandatory, 372 | ValueFromPipeline = $true 373 | )] 374 | [PSCustomObject] 375 | $FormattedResults 376 | ) 377 | 378 | $FormattedResults | Export-Csv -Path ("$outputDir\download_results-{0:MMddyy_HHmm}.csv" -f (Get-Date)) -NoTypeInformation -Force 379 | 380 | } #End function Invoke-CsvFormat 381 | 382 | function Invoke-HtmlFormat { #Begin function Invoke-HtmlFormat 383 | [cmdletbinding()] 384 | param( 385 | [Parameter(Mandatory)] 386 | [PSCustomObject] 387 | $FormattedResults 388 | ) 389 | 390 | $style = @" 391 | 397 | "@ 398 | 399 | $FormattedResults | ConvertTo-HTML -head $style | Out-File -FilePath ("$outputDir\download_results-{0:MMddyy_HHmm}.html" -f (Get-Date)) 400 | 401 | } #End function Invoke-HtmlFormat 402 | 403 | function Invoke-FileExtraction { #Begin function Invoke-FileExtraction 404 | [cmdletbinding()] 405 | param ( 406 | [Parameter( 407 | Mandatory 408 | )] 409 | $DownloadInfo 410 | ) 411 | 412 | Begin { 413 | 414 | $proceed = $false 415 | $zipAssembly = "System.IO.Compression.FileSystem" 416 | $assemblies = [System.AppDomain]::CurrentDomain.GetAssemblies() 417 | $reason = "Unable to load assembly!" 418 | 419 | if ($assemblies | Where-Object {$_.FullName -match $name}) { 420 | 421 | Add-Type -AssemblyName $zipAssembly 422 | $proceed = $true 423 | 424 | } 425 | 426 | if ($proceed -and !($DownloadInfo.FileInfo.FileName.SubString($DownloadInfo.FileInfo.FileName.LastIndexOf('.')+ 1) -eq 'zip')) { 427 | 428 | $proceed = $false 429 | $reason = "No zip file found!" 430 | 431 | } 432 | 433 | $returnObject = [PSCustomObject]@{ 434 | 435 | ExtractedTo = '' 436 | ExtractionSuccess = $false 437 | Error = '' 438 | 439 | } 440 | 441 | } 442 | 443 | Process { 444 | 445 | if ($proceed) { 446 | 447 | foreach ($download in $DownloadInfo) { 448 | 449 | if ($download.Success) { 450 | 451 | $extractTo = $null 452 | $extractFrom = $null 453 | 454 | $extractFrom = $download.FileInfo.LocalPath 455 | $extractTo = "$($extractFrom.Substring(0,$extractFrom.LastIndexOf('.')))_{0:HHmm-MMddyy}" -f (Get-Date) 456 | 457 | Write-Verbose "Attempting to extract [$extractFrom] -> [$extractTo]" 458 | 459 | Try { 460 | 461 | [IO.Compression.ZipFile]::ExtractToDirectory($extractFrom, $extractTo) 462 | 463 | $returnObject.ExtractionSuccess = $true 464 | $returnObject.ExtractedTo = $extractTo 465 | 466 | } 467 | Catch { 468 | 469 | $errorMessage = $_.Exception.Message 470 | 471 | Write-Error "[$errorMessage]" 472 | 473 | $returnObject.Error = $errorMessage 474 | 475 | } 476 | 477 | } 478 | 479 | } 480 | 481 | } else { 482 | 483 | Write-Error "[$reason]" 484 | 485 | } 486 | 487 | } 488 | 489 | End { 490 | 491 | Return $returnObject 492 | 493 | } 494 | 495 | } #End function Invoke-FileExtraction 496 | 497 | #Script actions, starting with checking the downloadName parameter value 498 | $fileCheck = Invoke-FileCheck -DownloadName $DownloadName 499 | 500 | foreach ($file in $fileCheck) { #Begin file/script foreach loop 501 | 502 | $result = $null 503 | 504 | $result = [PSCustomObject]@{ 505 | 506 | ScriptName = $file.ScriptName 507 | Success = $false 508 | Error = '' 509 | FileInfo = $null 510 | 511 | } 512 | 513 | if ($file.ScriptExists) { #Begin if for script existance 514 | 515 | try { 516 | 517 | Write-Verbose "Attempting to execute [$($file.ScriptPath)]" 518 | 519 | $getFile = Invoke-Expression -Command "$($file.ScriptPath) -matchText " 520 | 521 | } 522 | catch { 523 | 524 | $errorMessage = $_.Exception.Message 525 | $result.Error = $errorMessage 526 | 527 | $resultsArray.Add($result) | Out-Null 528 | 529 | Continue 530 | 531 | } 532 | 533 | if ($getFile.Success) { #Begin successful download actions 534 | 535 | $fileWriteResult = Invoke-FileWrite -Content $getFile.Content -LocalFolder $DownloadFolder -FileName $getFile.DownloadName 536 | 537 | if ($fileWriteResult.Error) { 538 | 539 | $result.Error = $fileWriteResult.Error 540 | 541 | } 542 | 543 | $result.FileInfo = $fileWriteResult 544 | $result.Success = $fileWriteResult.VerifiedToExist 545 | 546 | } else { #End successful download actions 547 | 548 | $result.Error = "Error getting [$downloadName] -> $($getFile.Error)" 549 | 550 | } 551 | 552 | } else { #Begin if/begin else for script existance 553 | 554 | $result.Error = "Script does not exist for [$downloadName]!" 555 | 556 | } 557 | 558 | Write-Verbose "Adding result for [$($getFile.DownloadName)] to results array!" 559 | 560 | $resultsArray.Add($result) | Out-Null 561 | 562 | } #End file/script foreach loop 563 | 564 | if ($UnZip) { #Begin UnZip actions 565 | 566 | Write-Verbose "Looking through downloads, and extracting any zips..." 567 | 568 | foreach ($result in $resultsArray) { #Begin foreach to iterate through results 569 | 570 | if ($result.Success) { #Only unzip successful results 571 | 572 | #This is to ensure we only target files with .zip extensions 573 | if ($result.FileInfo.FileName.Substring($result.FileInfo.FileName.LastIndexOf('.')+1) -eq 'zip') { 574 | 575 | $extractionResults = Invoke-FileExtraction $result 576 | 577 | $result.FileInfo | Add-Member -MemberType NoteProperty -Name 'ExtractionResults' -Value $extractionResults 578 | 579 | } 580 | 581 | } # End success if 582 | 583 | } #End results foreach 584 | 585 | } #End UnZip actions 586 | 587 | if ($OutputType) { #Begin if for outputType existing 588 | 589 | [System.Collections.ArrayList]$formattedObjectArray = @() 590 | 591 | foreach ($result in $resultsArray) { 592 | 593 | Write-Verbose "Working with [$($result.FileInfo.FileName)]" 594 | 595 | $formattedObject = $null 596 | $formattedObject = [PSCustomObject]@{ 597 | 598 | ScriptName = $result.ScriptName 599 | Success = $result.Success 600 | FileName = $result.FileInfo.FileName 601 | FilePath = $result.FileInfo.LocalPath 602 | Error = $result.Error 603 | VerifiedToExist = $result.FileInfo.VerifiedToExist 604 | 605 | } 606 | 607 | if ($result.FileInfo.ExtractionResults) { 608 | 609 | $formattedObject | Add-Member -MemberType NoteProperty -Name 'ExtractedTo' -Value $result.FileInfo.ExtractionResults.ExtractedTo 610 | $formattedObject | Add-Member -MemberType NoteProperty -Name 'ExtractionSuccess' -Value $result.FileInfo.ExtractionResults.ExtractionSuccess 611 | $formattedObject | Add-Member -MemberType NoteProperty -Name 'ExtractionError' -Value $result.FileInfo.ExtractionResults.Error 612 | 613 | } 614 | 615 | $formattedObjectArray.Add($formattedObject) | Out-Null 616 | 617 | } 618 | 619 | } #Enf if for outputType existing 620 | 621 | switch ($OutputType) { #Begin outputType switch 622 | 623 | 'html' { 624 | 625 | Write-Verbose "Formatting HTML..." 626 | 627 | Invoke-HTMLFormat -FormattedResults $formattedObjectArray 628 | 629 | Write-Verbose "HTML exported to [$outputDir]" 630 | 631 | } 632 | 633 | 'csv' { 634 | 635 | Write-Verbose "Formatting CSV..." 636 | 637 | Invoke-CsvFormat -FormattedResults $formattedObjectArray 638 | 639 | Write-Verbose "CSV exported to [$outputDir]" 640 | 641 | } 642 | 643 | 'xml' { 644 | 645 | Write-Verbose "Formatting XML..." 646 | 647 | $resultsArray | Export-Clixml -Path ("$outputDir\download_results-{0:MMddyy_HHmm}.xml" -f (Get-Date)) 648 | 649 | Write-Verbose "XML exported to [$outputDir]" 650 | 651 | } 652 | 653 | 'all' { 654 | 655 | Write-Verbose "Working on exporting as all formats (XML, CSV, and HTML)..." 656 | 657 | Invoke-HTMLFormat -FormattedResults $formattedObjectArray 658 | Invoke-CsvFormat -FormattedResults $formattedObjectArray 659 | $resultsArray | Export-Clixml -Path ("$outputDir\download_results-{0:MMddyy_HHmm}.xml" -f (Get-Date)) 660 | 661 | Write-Verbose "All formats (XML, CSV, and HTML) exported to [$outputDir]" 662 | 663 | } 664 | 665 | } #End outputType switch 666 | 667 | return $resultsArray --------------------------------------------------------------------------------