Private/GetWinPSInCore.ps1
function GetWinPSInCore { [CmdletBinding()] [Alias('shim')] Param ( [Parameter( Mandatory=$True, Position=0 )] [Alias("sb")] [scriptblock]$ScriptBlock, [Parameter(Mandatory=$False)] [switch]$MirrorCurrentEnv = $True, [Parameter(Mandatory=$False)] [switch]$NoWinRM ) if ($PSVersionTable.PSEdition -ne "Core" -or $PSVersionTable.Platform -ne "Win32NT") { Write-Error "The '$($MyInvocation.MyCommand.Name)' function is only meant to be used in PowerShell Core on Windows! Halting!" $global:FunctionResult = "1" return } if ($MirrorCurrentEnv) { [System.Collections.ArrayList]$SetEnvStringArray = @() $VariablesNotToForward = @() $Variables = Get-Variable if ($PSBoundParameters['VariablesToForward'] -and $VariablesToForward -notcontains '*') { $Variables = foreach ($VarObj in $Variables) { if ($VariablesToForward -contains $VarObj.Name) { $VarObj } } } $SetVarsPrep = foreach ($VarObj in $Variables) { if ($VariablesNotToForward -notcontains $VarObj.Name) { try { $VarValueAsJSON = $VarObj.Value | ConvertTo-Json -Compress } catch { #Write-Warning "Unable to pass the variable '$($VarObj.Name)'..." } if ($VarValueAsJSON) { if ([char[]]$VarObj.Name -contains '(' -or [char[]]$VarObj.Name -contains ' ') { $VarStringArr = @( 'try {' $(' ${' + $VarObj.Name + '}' + ' = ' + 'ConvertFrom-Json ' + "@'`n$VarValueAsJSON`n'@") '}' 'catch {' " Write-Verbose 'Unable to forward variable $($VarObj.Name)'" '}' ) } else { $VarStringArr = @( 'try {' $(' $' + $VarObj.Name + ' = ' + 'ConvertFrom-Json ' + "@'`n$VarValueAsJSON`n'@") '}' 'catch {' " Write-Verbose 'Unable to forward variable $($VarObj.Name)'" '}' ) } $VarStringArr -join "`n" } } } $SetVarsString = $SetVarsPrep -join "`n" $null = $SetEnvStringArray.Add($SetVarsString) # Set Environment Variables $EnvVariables = Get-ChildItem Env:\ if ($PSBoundParameters['EnvironmentVariablesToForward'] -and $EnvironmentVariablesToForward -notcontains '*') { $EnvVariables = foreach ($VarObj in $EnvVariables) { if ($EnvironmentVariablesToForward -contains $VarObj.Name) { $VarObj } } } $SetEnvVarsPrep = foreach ($VarObj in $EnvVariables) { if ([char[]]$VarObj.Name -contains '(' -or [char[]]$VarObj.Name -contains ' ') { $EnvStringArr = @( 'try {' $(' ${env:' + $VarObj.Name + '} = ' + "@'`n$($VarObj.Value)`n'@") '}' 'catch {' " Write-Verbose 'Unable to forward environment variable $($VarObj.Name)'" '}' ) } else { $EnvStringArr = @( 'try {' $(' $env:' + $VarObj.Name + ' = ' + "@'`n$($VarObj.Value)`n'@") '}' 'catch {' " Write-Verbose 'Unable to forward environment variable $($VarObj.Name)'" '}' ) } $EnvStringArr -join "`n" } $SetEnvVarsString = $SetEnvVarsPrep -join "`n" $null = $SetEnvStringArray.Add($SetEnvVarsString) # Set Modules $Modules = Get-Module if ($PSBoundParameters['ModulesToForward'] -and $ModulesToForward -notcontains '*') { $Modules = foreach ($ModObj in $Modules) { if ($ModulesToForward -contains $ModObj.Name) { $ModObj } } } $ModulesNotToForward = @('MiniLab') $SetModulesPrep = foreach ($ModObj in $Modules) { if ($ModulesNotToForward -notcontains $ModObj.Name) { $ModuleManifestFullPath = $(Get-ChildItem -Path $ModObj.ModuleBase -Recurse -File | Where-Object { $_.Name -eq "$($ModObj.Name).psd1" }).FullName $ModStringArray = @( '$tempfile = [IO.Path]::Combine([IO.Path]::GetTempPath(), [IO.Path]::GetRandomFileName())' "if (![bool]('$($ModObj.Name)' -match '\.WinModule')) {" ' try {' " Import-Module '$($ModObj.Name)' -ErrorAction Stop -WarningAction SilentlyContinue 2>`$tempfile" ' }' ' catch {' ' try {' " Import-Module '$ModuleManifestFullPath' -ErrorAction Stop -WarningAction SilentlyContinue 2>`$tempfile" ' }' ' catch {' " Write-Verbose 'Unable to Import-Module $($ModObj.Name)'" ' }' ' }' '}' 'if (Test-Path $tempfile) {' ' Remove-Item $tempfile -Force' '}' ) $ModStringArray -join "`n" } } $SetModulesString = $SetModulesPrep -join "`n" $null = $SetEnvStringArray.Add($SetModulesString) # Set Functions $Functions = Get-ChildItem Function:\ | Where-Object {![System.String]::IsNullOrWhiteSpace($_.Name)} if ($PSBoundParameters['FunctionsToForward'] -and $FunctionsToForward -notcontains '*') { $Functions = foreach ($FuncObj in $Functions) { if ($FunctionsToForward -contains $FuncObj.Name) { $FuncObj } } } $SetFunctionsPrep = foreach ($FuncObj in $Functions) { $FunctionText = Invoke-Expression $('@(${Function:' + $FuncObj.Name + '}.Ast.Extent.Text)') if ($($FunctionText -split "`n").Count -gt 1) { if ($($FunctionText -split "`n")[0] -match "^function ") { if ($($FunctionText -split "`n") -match "^'@") { Write-Warning "Unable to forward function $($FuncObj.Name) due to heredoc string: '@" } else { 'Invoke-Expression ' + "@'`n$FunctionText`n'@" } } } elseif ($($FunctionText -split "`n").Count -eq 1) { if ($FunctionText -match "^function ") { 'Invoke-Expression ' + "@'`n$FunctionText`n'@" } } } $SetFunctionsString = $SetFunctionsPrep -join "`n" $null = $SetEnvStringArray.Add($SetFunctionsString) } # Make sure we have Windows PowerShell PSModule Paths $PSCorePSModulePath = $env:PSModulePath [System.Collections.Arraylist][array]$PSCorePSModulePathArray = $env:PSModulePath -split ';' $WinPSPSModulePaths = @( 'C:\Program Files\WindowsPowerShell\Modules' "$HOME\Documents\WindowsPowerShell\Modules" 'C:\Windows\System32\WindowsPowerShell\v1.0\Modules' 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules' ) foreach ($ModPath in $WinPSPSModulePaths) { if ($PSCorePSModulePathArray -notcontains $ModPath) { $null = $PSCorePSModulePathArray.Add($ModPath) } } $FinalModPathString = $PSCorePSModulePathArray -join ';' # Create Initialization Scripts as needed... $InitSBAsStringA = "`$env:PSModulePath = '$FinalModPathString'`n" if ($SetEnvStringArray.Count -gt 0) { # Writing $SetEnvStringArray to a file helps us avoid the byte limit associated with the # -args parameter of powershell.exe. # See: http://systemcentersynergy.com/max-script-block-size-when-passing-to-powershell-exe-or-invoke-command/ $SetEnvStringArrayPath = "$HOME\SetEnvStringArray.xml" $SetEnvStringArray | Export-CliXml -Path $SetEnvStringArrayPath -Force $InitSBAsStringB = @( "`$args = Import-CliXml '$SetEnvStringArrayPath'" '' '$args | foreach {' ' if (![string]::IsNullOrWhiteSpace($_)) {' ' Invoke-Expression $_' ' }' '}' '' ) } if ($InitSBAsStringB) { # NOTE: $InitSBAsStringB coming before $InitSBAsStringA is important regarding $env:PSModulePath $FinalSBAsString = $InitSBAsStringB + $InitSBAsStringA + $ScriptBlock.ToString() } else { $FinalSBAsString = $InitSBAsStringA + $ScriptBlock.ToString() } try { $FinalSB = [scriptblock]::Create($($FinalSBAsString -join "`n")) } catch { Write-Error "Problem creating scriptblock `$FinalSB! Halting!" $global:FunctionResult = "1" return } # Output if ($NoWinRM) { powershell.exe -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -Command $FinalSB } else { # Check to see if there's a PSSession open from the WindowsCompatibility Module <# if (!$global:WinPSSession) { $CurrentUser = $($(whoami) -split '\\')[-1] if ([bool]$(Get-PSSession -Name "win-$CurrentUser" -ErrorAction SilentlyContinue)) { $global:WinPSSession = Get-PSSession -Name "win-$CurrentUser" } } #> $WinPSSessionName = NewUniqueString -PossibleNewUniqueString "WinPSSession" -ArrayOfStrings $(Get-PSSession).Name $NewPSSessionSplatParams = @{ ConfigurationName = 'Microsoft.PowerShell' Name = $WinPSSessionName EnableNetworkAccess = $True } $WinPSSession = New-PSSession @NewPSSessionSplatParams if (!$WinPSSession) { Write-Error "There was a problem creating the New-PSSession named 'WinPSSession'! Halting!" $global:FunctionResult = "1" return } else { Write-Host "A new PSSession called 'WinPSSession' has been created along with a Global Variable referencing it called `$global:WinPSSession." -ForegroundColor Green } Invoke-Command -Session $global:WinPSSession -ScriptBlock $FinalSB -HideComputerName } # Cleanup if ($SetEnvStringArrayPath) { if (Test-Path $SetEnvStringArrayPath) { #Remove-Item $SetEnvStringArrayPath -Force } } $WinPSSession | Remove-PSSession } |