From da8c4571162a13c09346c0e4fd93979e11744492 Mon Sep 17 00:00:00 2001 From: "Kim J. Nordmo" Date: Mon, 21 Mar 2022 10:07:44 +0100 Subject: [PATCH] (#5) Migrate core extension to repository --- src/chocolatey-core.extension/CHANGELOG.md | 71 ++++++++++++ src/chocolatey-core.extension/README.md | 50 +++++++++ .../chocolatey-core.extension.nuspec | 30 +++++ .../extensions/Get-AppInstallLocation.ps1 | 77 +++++++++++++ .../extensions/Get-AvailableDriveLetter.ps1 | 50 +++++++++ .../extensions/Get-EffectiveProxy.ps1 | 66 +++++++++++ .../extensions/Get-PackageCacheLocation.ps1 | 40 +++++++ .../extensions/Get-PackageParameters.ps1 | 35 ++++++ .../extensions/Get-UninstallRegistryKey.ps1 | 102 +++++++++++++++++ .../extensions/Get-WebContent.ps1 | 67 ++++++++++++ .../extensions/Register-Application.ps1 | 52 +++++++++ .../extensions/Remove-Process.ps1 | 103 ++++++++++++++++++ .../extensions/chocolatey-core.psm1 | 15 +++ 13 files changed, 758 insertions(+) create mode 100644 src/chocolatey-core.extension/CHANGELOG.md create mode 100644 src/chocolatey-core.extension/README.md create mode 100644 src/chocolatey-core.extension/chocolatey-core.extension.nuspec create mode 100644 src/chocolatey-core.extension/extensions/Get-AppInstallLocation.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Get-AvailableDriveLetter.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Get-EffectiveProxy.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Get-PackageCacheLocation.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Get-PackageParameters.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Get-UninstallRegistryKey.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Get-WebContent.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Register-Application.ps1 create mode 100644 src/chocolatey-core.extension/extensions/Remove-Process.ps1 create mode 100644 src/chocolatey-core.extension/extensions/chocolatey-core.psm1 diff --git a/src/chocolatey-core.extension/CHANGELOG.md b/src/chocolatey-core.extension/CHANGELOG.md new file mode 100644 index 0000000..9839389 --- /dev/null +++ b/src/chocolatey-core.extension/CHANGELOG.md @@ -0,0 +1,71 @@ +# CHANGELOG + +## 1.3.5 + +- Bugfix `Remove-Process`: Fixed Powershell v2 compatibility issue + +## 1.3.4 + +- Added `Remove-Process` function to ensure that process is stopped in reliable way + +## 1.3.3 + +- Bugfix `Get-AppInstallLocation`: fix path is directory + +## 1.3.2 + +- Bugfix `Get-AppInstallLocation`: now checks if path is directory + +## 1.3.1 +- Bugfix in `Get-AppInstallLocation`: Removed extra `$location` parameter from Split-Path when parsing the registry UninstallString. + +## 1.3.0 + +- `Get-EffectiveProxy`: Get the current proxy using several methods + +## 1.2.0 + +- Use `$IgnoredArguments` in all functions to allow for future expansion and splatting ([#621](https://github.com/chocolatey/chocolatey-coreteampackages/issues/621)) +- Bugfix in `Get-PackageParameters` parsing of paths containing symbol chars. + +## 1.1.0 +- `Get-AvailableDriveLetter`: Get the next unused drive letter + +## 1.0.7 +- Bugfix in `Get-PackageParameters`: flags can now have numbers in their names, whereas before, everything past the number would be truncated and the flag would turn into a boolean. + +## 1.0.6 +- Bugfix in `Get-AppInstallLocation`: Powershell 2 can not replace on null value. + +## 1.0.5 + +- Bugfix in `Get-UninstallRegistryKey`: Powershell 2 compatibility. +- Slightly improved documentation of `Get-UninstallRegistryKey`. + +## 1.0.4 + +- Bugfix in `Get-PackageParameters`: Powershell 2 bug workaround ([#465](https://github.com/chocolatey/chocolatey-coreteampackages/issues/465)). + +## 1.0.3 + +- Bugfix in `Get-PackageParameters`: error when parsing of path. + +## 1.0.2 + +- Bugfix in `Get-PackageParameters`: PowerShell 2 compatibility. + +## 1.0.1 + +- Bugfix in `Get-PackageParameters`: unaliased `sls` to work on PowerShell 2. + +## 1.0 + +- Merged `mm-choco.extension`. +- Merged `chocolatey-uninstall.extension`. +- Added `Get-PackageCacheLocation` +- Added `CHANGELOG.md` and `README.md`. +- Refactoring and more documentation. + +## 0.1.3 + +- `Get-WebContent`: Download file with choco internals. diff --git a/src/chocolatey-core.extension/README.md b/src/chocolatey-core.extension/README.md new file mode 100644 index 0000000..500e701 --- /dev/null +++ b/src/chocolatey-core.extension/README.md @@ -0,0 +1,50 @@ +# chocolatey-core.extension + +This is the Powershell module that extends Chocolatey with new functions. + +## Installation + +Install via chocolatey: `choco install chocolatey-core.extension`. + +The module is usually automatically installed as a dependency. + +## Usage + +To create a package that uses an extension function add the following to the `nuspec` specification: + + + + + +**NOTE**: Make sure you use adequate _minimum_ version. + +To test the functions you can import the module directly or via the `chocolateyInstaller.psm1` module: + + PS> import-module $Env:ChocolateyInstall\helpers\chocolateyInstaller.psm1 + PS> import-module $Env:ChocolateyInstall\extensions\chocolatey-core\*.psm1 + +You can now test any of the functions: + + PS> Get-AppInstallLocation choco -Verbose + + VERBOSE: Trying local and machine (x32 & x64) Uninstall keys + VERBOSE: Trying Program Files with 2 levels depth + VERBOSE: Trying PATH + C:\ProgramData\chocolatey\bin + +Keep in mind that function may work only in the context of the `chocolateyInstaller.ps1`. + +To get the list of functions, load the module directly and invoke the following command: + + Get-Command -Module chocolatey-core + +To get the help for the specific function use `man`: + + man Get-UninstallRegistryKey + + +## Notes + +- There is [a known bug](https://github.com/chocolatey-community/chocolatey-coreteampackages/issues/784) in the function `Get-AppInstallLocation` with parameter `$AppNamePattern` which is internally used both as wildcard and regex patterns. This usually doesn't create any problems, but may do so if application contains regex symbols in the name, such as [notepad++](https://github.com/chocolatey-community/chocolatey-coreteampackages/issues/1198). + + diff --git a/src/chocolatey-core.extension/chocolatey-core.extension.nuspec b/src/chocolatey-core.extension/chocolatey-core.extension.nuspec new file mode 100644 index 0000000..437b451 --- /dev/null +++ b/src/chocolatey-core.extension/chocolatey-core.extension.nuspec @@ -0,0 +1,30 @@ + + + + + chocolatey-core.extension + 1.3.5.1 + Chocolatey Core Extensions + Helper functions extending core choco functionality + chocolatey + chocolatey-community + +This package provides helper functions installed as a Chocolatey extension. +These functions may be used in Chocolatey install/uninstall scripts by declaring this package a dependency in your package's nuspec. + + chocolatey core extension admin + https://github.com/chocolatey/chocolatey-coreteampackages + + © 2016 Chocolatey Core Team Package Contributors + https://github.com/chocolatey/chocolatey-coreteampackages/blob/master/LICENSE.md + false + https://github.com/chocolatey/chocolatey-coreteampackages + https://github.com/chocolatey/chocolatey-coreteampackages/tree/master/extensions/chocolatey-core.extension + https://github.com/chocolatey/chocolatey-coreteampackages/tree/master/extensions/chocolatey-core.extension/README.md + https://github.com/chocolatey/chocolatey-coreteampackages/issues + https://github.com/chocolatey/chocolatey-coreteampackages/tree/master/extensions/chocolatey-core.extension/CHANGELOG.md + + + + + diff --git a/src/chocolatey-core.extension/extensions/Get-AppInstallLocation.ps1 b/src/chocolatey-core.extension/extensions/Get-AppInstallLocation.ps1 new file mode 100644 index 0000000..ef28520 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-AppInstallLocation.ps1 @@ -0,0 +1,77 @@ +. "$PSScriptRoot\Get-UninstallRegistryKey.ps1" +<# +.SYNOPSIS + Get application install location + +.DESCRIPTION + Function tries to find install location in multiple places. It returns $null if all fail. The following + locations are tried: + - local and machine (x32 & x64) various Uninstall keys + - x32 & x64 Program Files up to the 2nd level of depth + - native commands available via PATH + - locale and machine registry key SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths + + Use Verbose parameter to see which of the above locations was used for the result, if any. + +.EXAMPLE + PS> Get-AppInstallLocation choco + + Returns the install location of the application 'choco'. + +.OUTPUTS + [String] or $null +#> +function Get-AppInstallLocation { + [CmdletBinding()] + param( + # Regular expression pattern + [ValidateNotNullOrEmpty()] + [string] $AppNamePattern, + + # Allows splatting with arguments that do not apply and future expansion. Do not use directly. + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + + function strip($path) { if ($path.EndsWith('\')) { return $path -replace '.$' } else { $path } } + + function is_dir( $path ) { $path -and (gi $path -ea 0).PsIsContainer -eq $true } + + $ErrorActionPreference = "SilentlyContinue" + + Write-Verbose "Trying local and machine (x32 & x64) Uninstall keys" + [array] $key = Get-UninstallRegistryKey $AppNamePattern + if ($key.Count -eq 1) { + Write-Verbose "Trying Uninstall key property 'InstallLocation'" + $location = $key.InstallLocation + if (is_dir $location) { return strip $location } + + Write-Verbose "Trying Uninstall key property 'UninstallString'" + $location = $key.UninstallString + if ($location) { $location = $location.Replace('"', '') | Split-Path } + if (is_dir $location) { return strip $location } + + Write-Verbose "Trying Uninstall key property 'DisplayIcon'" + $location = $key.DisplayIcon + if ($location) { $location = Split-Path $location } + if (is_dir $location) { return strip $location } + } else { Write-Verbose "Found $($key.Count) keys, aborting this method" } + + $dirs = $Env:ProgramFiles, "$Env:ProgramFiles\*\*" + if (Get-ProcessorBits 64) { $dirs += ${ENV:ProgramFiles(x86)}, "${ENV:ProgramFiles(x86)}\*\*" } + Write-Verbose "Trying Program Files with 2 levels depth: $dirs" + $location = (ls $dirs | ? {$_.PsIsContainer}) -match $AppNamePattern | select -First 1 | % {$_.FullName} + if (is_dir $location) { return strip $location } + + Write-Verbose "Trying native commands on PATH" + $location = (Get-Command -CommandType Application) -match $AppNamePattern | select -First 1 | % { Split-Path $_.Source } + if (is_dir $location) { return strip $location } + + $appPaths = "\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths" + Write-Verbose "Trying Registry: $appPaths" + $location = (ls "HKCU:\$appPaths", "HKLM:\$appPaths") -match $AppNamePattern | select -First 1 + if ($location) { $location = Split-Path $location } + if (is_dir $location) { return strip $location } + + Write-Verbose "No location found" +} diff --git a/src/chocolatey-core.extension/extensions/Get-AvailableDriveLetter.ps1 b/src/chocolatey-core.extension/extensions/Get-AvailableDriveLetter.ps1 new file mode 100644 index 0000000..dad71b2 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-AvailableDriveLetter.ps1 @@ -0,0 +1,50 @@ +<# +.SYNOPSIS + Get a 'free' drive letter + +.DESCRIPTION + Get a not yet in-use drive letter that can be used for mounting + +.EXAMPLE + Get-AvailableDriveLetter + +.EXAMPLE + Get-AvailableDriveLetter 'X' + (do not return X, even if it'd be the next choice) + +.INPUTS + specific drive letter(s) that will be excluded as potential candidates + +.OUTPUTS + System.String (single drive-letter character) + +.LINK + http://stackoverflow.com/questions/12488030/getting-a-free-drive-letter/29373301#29373301 +#> +function Get-AvailableDriveLetter { + param ( + [char[]]$ExcludedLetters, + + # Allows splatting with arguments that do not apply and future expansion. Do not use directly. + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + + $Letter = [int][char]'C' + $i = @() + + #getting all the used Drive letters reported by the Operating System + $(Get-PSDrive -PSProvider filesystem) | %{$i += $_.name} + + #Adding the excluded letter + $i+=$ExcludedLetters + + while($i -contains $([char]$Letter)){$Letter++} + + if ($Letter -gt [char]'Z') { + throw "error: no drive letter available!" + } + Write-Verbose "available drive letter: '$([char]$Letter)'" + Return $([char]$Letter) +} + diff --git a/src/chocolatey-core.extension/extensions/Get-EffectiveProxy.ps1 b/src/chocolatey-core.extension/extensions/Get-EffectiveProxy.ps1 new file mode 100644 index 0000000..5356f9d --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-EffectiveProxy.ps1 @@ -0,0 +1,66 @@ +<# +.SYNOPSIS + Get the current proxy using several methods + +.DESCRIPTION + Function tries to find the current proxy using several methods, in the given order: + - $env:chocolateyProxyLocation variable + - $env:http_proxy environment variable + - IE proxy + - Chocolatey config + - Winhttp proxy + - WebClient proxy + + Use Verbose parameter to see which of the above locations was used for the result, if any. + The function currently doesn't handle the proxy username and password. + +.OUTPUTS + [String] in the form of http://: +#> +function Get-EffectiveProxy(){ + + # Try chocolatey proxy environment vars + if ($env:chocolateyProxyLocation) { + Write-Verbose "Using `$Env:chocolateyProxyLocation" + return $env:chocolateyProxyLocation + } + + # Try standard Linux variable + if ($env:http_proxy) { + Write-Verbose "Using `$Env:http_proxy" + return $env:http_proxy + } + + # Try to get IE proxy + $key = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" + $r = Get-ItemProperty $key + if ($r.ProxyEnable -and $r.ProxyServer) { + Write-Verbose "Using IE proxy settings" + return "http://" + $r.ProxyServer + } + + # Try chocolatey config file + [xml] $cfg = gc $env:ChocolateyInstall\config\chocolatey.config + $p = $cfg.chocolatey.config | % { $_.add } | ? { $_.key -eq 'proxy' } | select -Expand value + if ($p) { + Write-Verbose "Using choco config proxy" + return $p + } + + # Try winhttp proxy + (netsh.exe winhttp show proxy) -match 'Proxy Server\(s\)' | set proxy + $proxy = $proxy -split ' :' | select -Last 1 + $proxy = $proxy.Trim() + if ($proxy) { + Write-Verbose "Using winhttp proxy server" + return "http://" + $proxy + } + + # Try using WebClient + $url = "http://chocolatey.org" + $client = New-Object System.Net.WebClient + if ($client.Proxy.IsBypassed($url)) { return $null } + + Write-Verbose "Using WebClient proxy" + return "http://" + $client.Proxy.GetProxy($url).Authority +} diff --git a/src/chocolatey-core.extension/extensions/Get-PackageCacheLocation.ps1 b/src/chocolatey-core.extension/extensions/Get-PackageCacheLocation.ps1 new file mode 100644 index 0000000..3cd5291 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-PackageCacheLocation.ps1 @@ -0,0 +1,40 @@ +<# +.SYNOPSIS + Get temporary location for the package based on its name and version. + +.DESCRIPTION + The function returns package cache directory within $Env:TEMP. It will not create the directory + if it doesn't exist. + + This function is useful when you have to obtain the file using `Get-ChocolateyWebFile` in order + to perform certain installation steps that other helpers can't do. + +.EXAMPLE + Get-PackageCacheLocation + +.OUTPUTS + [String] + +.LINKS + Get-ChocolateyWebFile +#> +function Get-PackageCacheLocation { + [CmdletBinding()] + param ( + # Name of the package, by default $Env:ChocolateyPackageName + [string] $Name = $Env:ChocolateyPackageName, + # Version of the package, by default $Env:ChocolateyPackageVersion + [string] $Version = $Env:ChocolateyPackageVersion, + # Allows splatting with arguments that do not apply and future expansion. Do not use directly. + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + + if (!$Name) { Write-Warning 'Environment variable $Env:ChocolateyPackageName is not set' } + $res = Join-Path $Env:TEMP $Name + + if (!$Version) { Write-Warning 'Environment variable $Env:ChocolateyPackageVersion is not set' } + $res = Join-Path $res $Version + + $res +} diff --git a/src/chocolatey-core.extension/extensions/Get-PackageParameters.ps1 b/src/chocolatey-core.extension/extensions/Get-PackageParameters.ps1 new file mode 100644 index 0000000..5b77ff0 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-PackageParameters.ps1 @@ -0,0 +1,35 @@ +<# +.SYNOPSIS + Parses parameters of the package + +.EXAMPLE + Get-PackageParameters "/Shortcut /InstallDir:'c:\program files\xyz' /NoStartup" | set r + if ($r.Shortcut) {... } + Write-Host $r.InstallDir + +.OUTPUTS + [HashTable] +#> +function Get-PackageParameters { + [CmdletBinding()] + param( + [string] $Parameters = $Env:ChocolateyPackageParameters, + # Allows splatting with arguments that do not apply and future expansion. Do not use directly. + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + + $res = @{} + + $re = "\/([a-zA-Z0-9]+)(:[`"'].+?[`"']|[^ ]+)?" + $results = $Parameters | Select-String $re -AllMatches | select -Expand Matches + foreach ($m in $results) { + if (!$m) { continue } # must because of posh 2.0 bug: https://github.com/chocolatey/chocolatey-coreteampackages/issues/465 + + $a = $m.Value -split ':' + $opt = $a[0].Substring(1); $val = $a[1..100] -join ':' + if ($val -match '^(".+")|(''.+'')$') {$val = $val -replace '^.|.$'} + $res[ $opt ] = if ($val) { $val } else { $true } + } + $res +} diff --git a/src/chocolatey-core.extension/extensions/Get-UninstallRegistryKey.ps1 b/src/chocolatey-core.extension/extensions/Get-UninstallRegistryKey.ps1 new file mode 100644 index 0000000..6431f44 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-UninstallRegistryKey.ps1 @@ -0,0 +1,102 @@ +<# +.SYNOPSIS + Retrieve registry key(s) for system-installed applications from an exact or wildcard search. + +.DESCRIPTION + This function will attempt to retrieve a matching registry key for an already installed application, + usually to be used with a chocolateyUninstall.ps1 automation script. + + The function also prevents `Get-ItemProperty` from failing when handling wrongly encoded registry keys. + +.PARAMETER SoftwareName + Part or all of the Display Name as you see it in Programs and Features. + It should be enough to be unique. + The syntax follows the rules of the PowerShell `-like` operator, so the `*` character is interpreted + as a wildcard, which matches any (zero or more) characters. + + If the display name contains a version number, such as "Launchy (2.5)", it is recommended you use a + fuzzy search `"Launchy (*)"` (the wildcard `*`) so if Launchy auto-updates or is updated outside + of chocolatey, the uninstall script will not fail. + + Take care not to abuse fuzzy/glob pattern searches. Be conscious of programs that may have shared + or common root words to prevent overmatching. For example, "SketchUp*" would match two keys with software + names "SketchUp 2016" and "SketchUp Viewer" that are different programs released by the same company. + +.PARAMETER IgnoredArguments + Allows splatting with arguments that do not apply and future expansion. Do not use directly. + +.INPUTS + System.String + +.OUTPUTS + PSCustomObject + +.EXAMPLE + [array]$key = Get-UninstallRegistryKey -SoftwareName "VLC media player" + $key.UninstallString + + Exact match: software name in Programs and Features is "VLC media player" + +.EXAMPLE + [array]$key = Get-UninstallRegistryKey -SoftwareName "Gpg4win (*)" + $key.UninstallString + + Version match: software name is "Gpg4Win (2.3.0)" + +.EXAMPLE + [array]$key = Get-UninstallRegistryKey -SoftwareName "SketchUp [0-9]*" + $key.UninstallString + + Version match: software name is "SketchUp 2016" + Note that the similar software name "SketchUp Viewer" would not be matched. + +.LINK + Uninstall-ChocolateyPackage +#> +function Get-UninstallRegistryKey { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true, ValueFromPipeline=$true)] + [ValidateNotNullOrEmpty()] + [string] $SoftwareName, + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + Write-Debug "Running 'Get-UninstallRegistryKey' for `'$env:ChocolateyPackageName`' with SoftwareName:`'$SoftwareName`'"; + + $ErrorActionPreference = 'Stop' + $local_key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' + $machine_key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' + $machine_key6432 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' + + Write-Verbose "Retrieving all uninstall registry keys" + [array]$keys = Get-ChildItem -Path @($machine_key6432, $machine_key, $local_key) -ea 0 + Write-Debug "Registry uninstall keys on system: $($keys.Count)" + + Write-Debug "Error handling check: `'Get-ItemProperty`' fails if a registry key is encoded incorrectly." + [int]$maxAttempts = $keys.Count + for ([int]$attempt = 1; $attempt -le $maxAttempts; $attempt++) + { + $success = $false + + $keyPaths = $keys | Select-Object -ExpandProperty PSPath + try { + [array]$foundKey = Get-ItemProperty -Path $keyPaths -ea 0 | ? { $_.DisplayName -like $SoftwareName } + $success = $true + } catch { + Write-Debug "Found bad key." + foreach ($key in $keys){ try{ Get-ItemProperty $key.PsPath > $null } catch { $badKey = $key.PsPath }} + Write-Verbose "Skipping bad key: $badKey" + [array]$keys = $keys | ? { $badKey -NotContains $_.PsPath } + } + + if ($success) { break; } + if ($attempt -eq 10) { + Write-Warning "Found more than 10 bad registry keys. Run command again with `'--verbose --debug`' for more info." + Write-Debug "Each key searched should correspond to an installed program. It is very unlikely to have more than a few programs with incorrectly encoded keys, if any at all. This may be indicative of one or more corrupted registry branches." + } + } + + Write-Debug "Found $($foundKey.Count) uninstall registry key(s) with SoftwareName:`'$SoftwareName`'"; + return $foundKey +} diff --git a/src/chocolatey-core.extension/extensions/Get-WebContent.ps1 b/src/chocolatey-core.extension/extensions/Get-WebContent.ps1 new file mode 100644 index 0000000..6e9287e --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Get-WebContent.ps1 @@ -0,0 +1,67 @@ +<# +.SYNOPSIS + Download file with choco internals + +.DESCRIPTION + This function will download a file from specified url and return it as a string. + This command should be a replacement for ubiquitous WebClient in install scripts. + + The benefit of using this command instead of WebClient is that it correctly handles + system or explicit proxy. + +.EXAMPLE + PS C:\> $s = Get-WebContent "http://example.com" + PS C:\> $s -match 'Example Domain' + True + + First command downloads html content from http://example.com and stores it in $s. + Now you can parse and match it as a string. + +.EXAMPLE + PS C:\> $opts = @{ Headers = @{ Referer = 'http://google.com' } } + PS C:\> $s = Get-WebContent -url "http://example.com" -options $opts + + You can set headers for http request this way. + +.INPUTS + None + +.OUTPUTS + System.String + +.NOTES + This function can only return string content. + If you want to download a binary content, please use Get-WebFile. + +.LINK + Get-WebFile +#> +function Get-WebContent { + [CmdletBinding()] + param( + # Url to download + [string]$Url, + + # Additional options for http request.For now only Headers property supported. + [hashtable]$Options, + + # Allows splatting with arguments that do not apply and future expansion. Do not use directly. + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + + $filePath = get_temp_filepath + Get-WebFile -Url $Url -FileName $filePath -Options $Options 3>$null + + $fileContent = Get-Content $filePath -ReadCount 0 | Out-String + Remove-Item $filePath + + $fileContent +} + +function get_temp_filepath() { + $tempDir = Get-PackageCacheLocation + $fileName = [System.IO.Path]::GetRandomFileName() + Join-Path $tempDir $fileName +} + diff --git a/src/chocolatey-core.extension/extensions/Register-Application.ps1 b/src/chocolatey-core.extension/extensions/Register-Application.ps1 new file mode 100644 index 0000000..c525db6 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Register-Application.ps1 @@ -0,0 +1,52 @@ +<# +.SYNOPSIS + Register application in the system + +.DESCRIPTION + The function will register application in the system using App Paths registry key so that you + can start it by typing its registred name in the Windows Start menu on using run dialog (Win + R). + + To make applications available in the shell, add to your profile Set-AppKeyAliases function. + +.EXAMPLE + Register-Application 'c:\windows\notepad.exe' + + Register application using name derived from its file name. + +.EXAMPLE + Register-Application 'c:\windows\notepad.exe' -Name ntp + + Register application using explicit name. + +.LINK + Set-AppKeyAliases - https://github.com/majkinetor/posh/blob/master/MM_Admin/Set-AppKeyAliases.ps1 + Application Registration - https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx + +#> +function Register-Application{ + [CmdletBinding()] + param( + # Full path of the executable to register. + [Parameter(Mandatory=$true)] + [string]$ExePath, + + # Optional name to register with. By default exe name will be used. + [string]$Name, + + # Register application only for the current user. By default registration is for the machine. + [switch]$User, + + # Allows splatting with arguments that do not apply and future expansion. Do not use directly. + [parameter(ValueFromRemainingArguments = $true)] + [Object[]] $IgnoredArguments + ) + + if (!(Test-Path $ExePath)) { throw "Path doesn't exist: $ExePath" } + if (!$Name) { $Name = Split-Path $ExePath -Leaf } else { $Name = $Name + '.exe' } + + $appPathKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$Name" + if ($User) { $appPathKey = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$Name" } + + If (!(Test-Path $AppPathKey)) { New-Item "$AppPathKey" | Out-Null } + Set-ItemProperty -Path $AppPathKey -Name "(Default)" -Value $ExePath +} diff --git a/src/chocolatey-core.extension/extensions/Remove-Process.ps1 b/src/chocolatey-core.extension/extensions/Remove-Process.ps1 new file mode 100644 index 0000000..857e0c3 --- /dev/null +++ b/src/chocolatey-core.extension/extensions/Remove-Process.ps1 @@ -0,0 +1,103 @@ +<# +.SYNOPSIS + Ensure that process is stopped in reliable way + +.DESCRIPTION + Close the processes matching filters gracefully first, then forcefully. + If no process is found, function will simply do and return nothing. + +.EXAMPLE + notepad; Remove-Process notepad -PathFilter 'system32' + + Close main window of notepad that has 'system32' word in its path + +.EXAMPLE + Remove-Process notepad -WaitFor 30 + notepad; notepad #in another shell + + Close all instances of notepad but wait for them up to 30 seconds to start + +.OUTPUTS + Array of closeed processes with details about each one. + +.NOTES + https://github.com/chocolatey-community/chocolatey-coreteampackages/issues/1364 +#> + +function Remove-Process { + param( + # RegEx expression of process name, returned by Get-Process function + [string] $NameFilter, + + # RegEx expression of process path, returned by Get-Process function + [string] $PathFilter, + + # Wait for process to start number of seconds + # Function will try to find process every second until timeout. + [int] $WaitFor, + + # Close/Kill child processes, by default they are filtered out as + # parent-child relationship usually have its own heartbeat feature + [switch] $WithChildren + ) + + function getp { + foreach ($p in Get-Process) { + $b1 = if ($NameFilter) { $p.ProcessName -match $NameFilter } + $b2 = if ($PathFilter) { $p.Path -match $PathFilter } + $b = if (($b1 -ne $null) -and ($b2 -ne $null)) { $b1 -and $b2 } else { $b1 -or $b2 } + if (!$b) { continue } + + $w = Get-WmiObject win32_process -Filter "ProcessId = $($p.Id)" + [PSCustomObject]@{ + Id = $p.Id + ParentId = $w.ParentProcessId + Name = $p.ProcessName + Path = $p.Path + CommandLine = $w.CommandLine + Process = $p + Username = $w.GetOwner().Domain + "\"+ $w.GetOwner().User + } + } + } + + $proc = getp + if (!$proc -and $WaitFor) { + Write-Verbose "Waiting for process up to $WaitFor seconds" + for ($i=0; $i -lt $WaitFor; $i++) { Start-Sleep 1; $proc = getp; if ($proc) {break} } + } + if (!$proc) { return } + + # Process might spawn multiple children, typical for browsers; remove all children as parent will handle them + if (!$WithChildren) { + Write-Verbose "Remove all children processes" + $proc = $proc | ? { $proc.Id -notcontains $_.ParentId } + } + + foreach ($p in $proc) { + Write-Verbose "Trying to close app '$($p.Name)' run by user '$($p.Username)'" + + if ( $p.Process.CloseMainWindow() ) { + # wait for app to shut down for some time, max 5s + for ($i=0; $i -lt 5; $i++) { + Start-Sleep 1 + $p2 = ps -PID $p.id -ea 0 + if (!$p2) { break } + } + } + + # Return value of CloseMainWindow() 'True' is not reliable + # so if process is still active kill it + $p2 = ps -PID $p.id -ea 0 + if (($p.Process.Name -eq $p2.Name) -and ($p.Process.StartTime -eq $p2.StartTime)) { + $p | Stop-Process -ea STOP + Start-Sleep 1 # Running to fast here still gets the killed process in next line + } + + $p2 = ps -PID $p.id -ea 0 + if (($p.Process.Name -eq $p2.Name) -and ($p.Process.StartTime -eq $p2.StartTime)) { + Write-Warning "Process '$($p.Name)' run by user '$($p.Username)' can't be closed" + } + } + $proc +} diff --git a/src/chocolatey-core.extension/extensions/chocolatey-core.psm1 b/src/chocolatey-core.extension/extensions/chocolatey-core.psm1 new file mode 100644 index 0000000..47f413a --- /dev/null +++ b/src/chocolatey-core.extension/extensions/chocolatey-core.psm1 @@ -0,0 +1,15 @@ +# Export functions that start with capital letter, others are private +# Include file names that start with capital letters, ignore others +$ScriptRoot = Split-Path $MyInvocation.MyCommand.Definition + +$pre = Get-ChildItem Function:\* +Get-ChildItem "$ScriptRoot\*.ps1" | + Where-Object { $_.Name -cmatch '^[A-Z]+' } | + ForEach-Object { . $_ } +$post = Get-ChildItem Function:\* +$funcs = Compare-Object $pre $post | + Select-Object -ExpandProperty InputObject | + Select-Object -ExpandProperty Name +$funcs | + Where-Object { $_ -cmatch '^[A-Z]+'} | + ForEach-Object { Export-ModuleMember -Function $_ } \ No newline at end of file