SecureFetch.psm1
|
foreach ($loaded in Get-Module -Name 'SecureFetch' -All) { $same = if ([System.IO.Path]::DirectorySeparatorChar -eq '\') { $loaded.ModuleBase -eq $PSScriptRoot } else { $loaded.ModuleBase -ceq $PSScriptRoot } if ($same) { continue } if ($loaded.ModuleType -eq 'Script' -and $null -ne (& $loaded { $ExecutionContext.SessionState.PSVariable.GetValue('PwrsStoodDownFor') })) { continue } if ($loaded.Version -eq [version]'0.2.0') { Microsoft.PowerShell.Utility\Write-Verbose ('SecureFetch' + ' ' + '0.2.0' + ' is already loaded from ' + $loaded.ModuleBase + ', so the copy at ' + $PSScriptRoot + ' is not loaded.') $ExecutionContext.SessionState.PSVariable.Set('PwrsStoodDownFor', $loaded.ModuleBase) return } throw [System.Management.Automation.ErrorRecord]::new([System.InvalidOperationException]::new('SecureFetch' + ' ' + $loaded.Version + ' is already loaded from ' + $loaded.ModuleBase + ', and a session can have only one version of a module, so ' + 'SecureFetch' + ' ' + '0.2.0' + ' at ' + $PSScriptRoot + ' is not loaded.'), 'PwrsOtherVersionLoaded', [System.Management.Automation.ErrorCategory]::ResourceExists, $loaded) } $root = $PSScriptRoot $tfm = if ($PSVersionTable.PSEdition -eq 'Core') { 'net10.0' } else { 'netstandard2.0' } $pwrsLoad = [System.AppDomain]::CurrentDomain.GetData('pwrs-load') if ($null -eq $pwrsLoad) { $pwrsLoad = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'pwrs-load') if ($tfm -eq 'net10.0' -and -not $IsWindows) { $pwrsUid = $null $pwrsProbe = [System.IO.Path]::GetTempFileName() try { $pwrsUid = $ExecutionContext.InvokeProvider.Item.Get([string[]]@($pwrsProbe), $true, $true)[0].UnixStat.UserId } finally { [System.IO.File]::Delete($pwrsProbe) } $pwrsMine = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'pwrs-load-' + $pwrsUid) $pwrsPrivate = [System.IO.UnixFileMode]'UserRead, UserWrite, UserExecute' $pwrsStat = $null $pwrsWhy = '' if ($null -ne $pwrsUid) { try { $null = [System.IO.Directory]::CreateDirectory($pwrsMine, $pwrsPrivate) $pwrsStat = $ExecutionContext.InvokeProvider.Item.Get([string[]]@($pwrsMine), $true, $true)[0].UnixStat } catch [System.IO.IOException], [System.UnauthorizedAccessException] { # A file by that name, or a folder this user cannot read: the # check below takes it as not this user's, and the warning # gives the error's message. $pwrsWhy = ' (' + $_.Exception.Message + ')' } } if ($null -ne $pwrsStat -and $pwrsStat.UserId -eq $pwrsUid -and [string]$pwrsStat.ItemType -eq 'Directory') { if (($pwrsStat.Mode -band 63) -ne 0) { [System.IO.File]::SetUnixFileMode($pwrsMine, $pwrsPrivate) } $pwrsLoad = $pwrsMine } else { $pwrsLoad = [System.IO.Directory]::CreateTempSubdirectory('pwrs-load-').FullName Microsoft.PowerShell.Utility\Write-Warning ('pwrs: ' + $pwrsMine + ' is not a folder of this user''s own' + $pwrsWhy + ', so this session stages its copies in ' + $pwrsLoad + ', which no other session uses.') } } [System.AppDomain]::CurrentDomain.SetData('pwrs-load', $pwrsLoad) } if (-not ('Pwrs.Bootstrap.Loader' -as [type])) { $stage = [System.IO.Path]::Combine($pwrsLoad, [string]$PID, 'boot', '877a0aad59d8d4a3', $tfm) $null = [System.IO.Directory]::CreateDirectory($stage) $boot = [System.IO.Path]::Combine($stage, 'Pwrs.Bootstrap.dll') if (-not [System.IO.File]::Exists($boot)) { $pdb = [System.IO.Path]::Combine($root, $tfm, 'Pwrs.Bootstrap.pdb') $bootPdb = [System.IO.Path]::Combine($stage, 'Pwrs.Bootstrap.pdb') if ([System.IO.File]::Exists($pdb) -and -not [System.IO.File]::Exists($bootPdb)) { $partial = $bootPdb + '.' + [System.Guid]::NewGuid().ToString('N') + '.partial' [System.IO.File]::Copy($pdb, $partial) try { [System.IO.File]::Move($partial, $bootPdb) } catch [System.IO.IOException] { [System.IO.File]::Delete($partial) if (-not [System.IO.File]::Exists($bootPdb)) { throw } } } $partial = $boot + '.' + [System.Guid]::NewGuid().ToString('N') + '.partial' [System.IO.File]::Copy([System.IO.Path]::Combine($root, $tfm, 'Pwrs.Bootstrap.dll'), $partial) try { [System.IO.File]::Move($partial, $boot) } catch [System.IO.IOException] { [System.IO.File]::Delete($partial) if (-not [System.IO.File]::Exists($boot)) { throw } } } $null = [System.Reflection.Assembly]::LoadFrom($boot) } try { $shell = [Pwrs.Bootstrap.Loader]::Load($root, 'SecureFetch', $tfm) } catch { if ($tfm -eq 'net10.0' -and [Environment]::Version.Major -lt 8) { throw ('SecureFetch' + ' needs PowerShell 7.4 or later: its PowerShell 7 half is built against .NET 8, and this is PowerShell ' + $PSVersionTable.PSVersion + ' on .NET ' + [Environment]::Version + '.') } throw } $shell.GetType('Pwrs.Modules.SecureFetch.PwrsModuleRoot', $true).GetField('Value').SetValue($null, $root) if ($tfm -eq 'netstandard2.0') { $staged = [System.IO.Path]::GetDirectoryName($shell.Location) foreach ($dep in @('System.Security.AccessControl.dll', 'System.Security.Principal.Windows.dll', 'System.IO.FileSystem.AccessControl.dll', 'Microsoft.Win32.Registry.dll')) { $to = [System.IO.Path]::Combine($staged, $dep) if (-not [System.IO.File]::Exists($to)) { $partial = $to + '.' + [System.Guid]::NewGuid().ToString('N') + '.partial' [System.IO.File]::Copy([System.IO.Path]::Combine($root, $tfm, $dep), $partial) try { [System.IO.File]::Move($partial, $to) } catch [System.IO.IOException] { [System.IO.File]::Delete($partial) if (-not [System.IO.File]::Exists($to)) { throw } } } } } foreach ($m in Get-Module -All) { if ($m.ModuleType -eq 'Binary' -and ($m.Path -eq $shell.Location -or $m.Name -like '*SecureFetch.Shell*')) { Remove-Module -ModuleInfo $m -Force -ErrorAction SilentlyContinue } } try { Import-Module -Assembly $shell -Force $reload = $null foreach ($type in $shell.GetTypes()) { if ($type.Name -eq 'PwrsModule') { $reload = $type; break } } if ($null -ne $reload) { $null = $reload::ReloadNative() } } catch { $inner = $_.Exception while ($null -ne $inner.InnerException -and $inner.GetType().FullName -ne 'Pwrs.PwrsException') { $inner = $inner.InnerException } if ($inner -is [System.Management.Automation.IContainsErrorRecord]) { throw $inner.ErrorRecord } throw $inner } Export-ModuleMember -Cmdlet 'Invoke-SecureFetch' -Alias @() |