Universal.psm1
Import-Module "$PSScriptRoot\UniversalDashboard.MaterialUI.psm1" -ErrorAction SilentlyContinue if (-not $IsCoreCLR) { Import-Module "$PSScriptRoot\Assemblies\System.Runtime.CompilerServices.Unsafe.dll" } $TAType = [psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators') $TAtype::Add('File', 'PowerShellUniversal.PSUFile') $TAtype::Add('Documentation', 'PowerShellUniversal.DocumentationAttribute') $TAtype::Add('Component', 'PowerShellUniversal.ComponentAttribute') function Start-PSUServer { [CmdletBinding(DefaultParameterSetName = "Service")] param( [Parameter(ParameterSetName = 'Path')] [string]$ExecutablePath, [Parameter(ParameterSetName = 'Path')] [string]$ListenAddress, [Parameter(ParameterSetName = 'Path')] [int]$Port, [Parameter(ParameterSetName = 'Path')] [ScriptBlock]$Configuration ) if ($MyInvocation.BoundParameters.Count -eq 0) { Start-Service 'PowerShellUniversal' return } if ([UniversalAutomation.RemoteCommand]::Configuration) { & $Configuration return } if (-not $PSBoundParameters.ContainsKey("ExecutablePath")) { $ExecutablePath = "Universal.Server" if ($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) { $ExecutablePath = "Universal.Server.exe" } } $Command = Get-Command $ExecutablePath -ErrorAction SilentlyContinue if ($null -eq $Command) { $ExecutablePath = Join-Path $PSScriptRoot $ExecutablePath $Command = Get-Command $ExecutablePath -ErrorAction SilentlyContinue if ($null -eq $Command) { throw 'Unable to locate the Universal Server executable. You can use Install-PSUServer the server for your platform. Use the -AddToPath parameter to add the installation directory the the PATH.' } } if ($PSVersionTable.PSEdition -ne 'Desktop' -and -not $IsWindows) { try { chmod +x $ExecutablePath } catch { Write-Warning "Failed to set executable flag. You may have to run 'chmod +x' yourself on $ExecutablePath. $_" } } if ($ListenAddress) { $Env:Kestrel__Endpoints__HTTP__Url = $ListenAddress } elseif ($PSBoundParameters.ContainsKey("Port")) { $Env:Kestrel__Endpoints__HTTP__Url = "http://*:$port" } if ($Configuration) { $scriptName = (Get-PSCallStack | Select-Object -Last 1).ScriptName if (-not $scriptName) { $scriptName = (Get-PSCallStack | Select-Object -Last 1 -Skip 1).ScriptName } $Env:Data__ConfigurationScript = $scriptName } $Process = Start-Process -FilePath $ExecutablePath -PassThru $Process } function Install-PSUServer { <# .SYNOPSIS Install the PowerShell Universal server. .DESCRIPTION Install the PowerShell Universal server. This is a convenience function that will install the server for your platform. On Windows, it will install the server as a Windows service. On Linux, it will install the server as a systemd service. On Mac, it will install the server as a launchd service. .PARAMETER Path The path to store the PowerShell Universal binaries. If not specified, the default installation path will be used. .PARAMETER AddToPath Whether to add the path to the PATH environment variable. .PARAMETER Version The version of PowerShell Universal to install. .PARAMETER LatestVersion Install the most recent version. .EXAMPLE Install-PSUServer #> [CmdletBinding(DefaultParameterSetName = "Version")] param( [Parameter()] [string]$Path, [Parameter(ParameterSetName = "Version")] [string]$Version = (Get-Module Universal).Version, [Parameter(ParameterSetName = "Latest")] [Switch]$LatestVersion, [Parameter()] [string]$IISWebsite, [Parameter()] [string]$IISAppPool = "PowerShellUniversal", [Parameter()] [int]$IISPort ) if ($IISWebsite -and ($IsLinux -or $IsMacOS)) { throw "IISWebsite is only supported on Windows." } if ($IISWebsite) { Import-Module WebAdministration -ErrorAction Stop } if ($platform -eq 'win-x64' -and -not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { throw 'You must be an administrator to install the Universal Server. Please run the command as an administrator.' } $platform = "win-x64"; $folder = 'CommonApplicationData' if ($PSVersionTable.PSEdition -eq 'Core') { if ($IsLinux) { $platform = "linux-x64" } elseif ($IsMacOS) { $folder = 'ApplicationData' $platform = "osx-x64" } } if (-not $Path -and -not $IISWebsite) { $ProgramData = [System.Environment]::GetFolderPath($folder) $Path = [System.IO.Path]::Combine($ProgramData, "PowerShellUniversal", "Server") } if (-not $Path -and $IISWebsite) { $Path = "C:\inetpub\wwwroot\PowerShellUniversal" New-Item $Path -ItemType Directory | Out-Null } if ($LatestVersion) { $Version = (Invoke-WebRequest https://imsreleases.blob.core.windows.net/universal/production/v5-version.txt).Content } Write-Verbose "Downloading version $Version" if (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { $Temp = [System.IO.Path]::GetTempPath() $Msi = (Join-Path $Temp "Universal.$Version.$platform.msi") Remove-Item $Msi -Force -ErrorAction SilentlyContinue Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$version/PowerShellUniversal.$Version.msi" -OutFile $Msi Write-Verbose "Download complete. Installing from MSI." Start-Process msiexec.exe -ArgumentList "/i $Msi /quiet /qn /norestart" -Wait } else { Write-Verbose "Installing server to $Path" $Temp = [System.IO.Path]::GetTempPath() $Zip = (Join-Path $Temp "Universal.$Version.$platform.zip") Remove-Item $Zip -Force -ErrorAction SilentlyContinue Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$version/Universal.$platform.$Version.zip" -OutFile $Zip Write-Verbose "Download complete. Unzipping to $Path" Expand-Archive -Path $Zip -DestinationPath $Path -Force Remove-Item $Zip -Force } if ($IISWebsite) { New-WebAppPool -Name $IISAppPool | Out-Null New-Website -Name $IISWebsite -Port $IISPort -PhysicalPath $Path -ApplicationPool $IISAppPool | Out-Null Start-Website -Name $IISWebsite } if ($IsMacOS -or $IsLinux) { $ServerPath = Join-Path $Path "Universal.Server" /bin/chmod +x $ServerPath } if ($IsLinux) { Write-Verbose "Creating and starting PowerShellUniversal service" touch /etc/systemd/system/PowerShellUniversal.service chmod 664 /etc/systemd/system/PowerShellUniversal.service "[Unit] Description=PowerShell Universal [Service] ExecStart=$Path/Universal.Server [Install] WantedBy=multi-user.target" | Out-File /etc/systemd/system/PowerShellUniversal.service systemctl daemon-reload systemctl start PowerShellUniversal systemctl enable PowerShellUniversal } if ($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) { } else { Write-Verbose "Adding $Path to `$PATH variable" $PathSeparator = ":" $envPath = [Environment]::GetEnvironmentVariable('PATH') $newpath = $envPath + $PathSeparator + $Path [Environment]::SetEnvironmentVariable("PATH", $newpath) } $Env:PATH += $PathSeparator + $Path } function Update-PSUServer { <# .SYNOPSIS Update the PowerShell Universal server. .DESCRIPTION Update the PowerShell Universal server. This is a convenience function that will update the server for your platform. .PARAMETER Path The path for the PowerShell Universal binaries. If not specified, the path will attempt to be resolved. .PARAMETER Version The version to upgrade to. .PARAMETER LatestVersion Upgrade to the latest version. .EXAMPLE Update-PSUServer #> [CmdletBinding(DefaultParameterSetName = "Version")] param( [Parameter()] [string]$Path, [Parameter(ParameterSetName = "Version")] [string]$Version = (Get-Module Universal).Version, [Parameter(ParameterSetName = "Latest")] [Switch]$LatestVersion, [Parameter()] [string]$IISWebsite ) $platform = "win-x64"; if ($PSVersionTable.PSEdition -eq 'Core') { if ($IsLinux) { $platform = "linux-x64" } elseif ($IsMacOS) { $platform = "osx-x64" } } if ($platform -eq 'win-x64' -and -not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { throw 'You must be an administrator to update the Universal Server. Please run the command as an administrator.' } if ($IISWebsite -and ($IsLinux -or $IsMacOS)) { throw "IISWebsite is only supported on Windows." } if ($IISWebsite) { Import-Module WebAdministration -ErrorAction Stop } if (-not $Path -and -not $IISWebsite) { if ($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) { $ServerPath = Get-Command "Universal.Server.exe" -ErrorAction SilentlyContinue } else { $ServerPath = Get-Command "Universal.Server" -ErrorAction SilentlyContinue } if (-not $ServerPath) { throw "Unable to locate existing PowerShell Universal installation. Use the -Path parameter to specify the folder of the previous installation." } $Path = [System.IO.Path]::GetDirectoryName($ServerPath.Source) } if (-not $Path -and $IISWebsite) { $Path = (Get-Website -Name $IISWebsite).PhysicalPath } if ($LatestVersion) { $Version = (Invoke-WebRequest https://imsreleases.blob.core.windows.net/universal/production/v5-version.txt).Content } if (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { $Temp = [System.IO.Path]::GetTempPath() $Msi = (Join-Path $Temp "Universal.$Version.$platform.msi") Remove-Item $Msi -Force -ErrorAction SilentlyContinue Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$version/PowerShellUniversal.$Version.msi" -OutFile $Msi Write-Verbose "Download complete. Installing from MSI." Start-Process msiexec.exe -ArgumentList "/i $Msi /quiet /qn /norestart" -Wait } else { Write-Verbose "Upgrading server installed at $Path" Write-Verbose "Downloading version $Version" $Temp = [System.IO.Path]::GetTempPath() $Zip = (Join-Path $Temp "Universal.$Version.$platform.zip") Remove-Item $Zip -Force -ErrorAction SilentlyContinue if ($IISWebsite) { $AppPool = (Get-Website -Name $IISWebsite).ApplicationPool Stop-Website -Name $IISWebsite Stop-WebAppPool -Name $AppPool } if ($IsLinux) { Write-Verbose "Stopped PowerShellUniversal service" systemctl stop PowerShellUniversal systemctl disable PowerShellUniversal } Remove-Item $Path -Force -Recurse Invoke-WebRequest "https://imsreleases.blob.core.windows.net/universal/production/$version/Universal.$platform.$Version.zip" -OutFile $Zip Write-Verbose "Download complete. Extracting to $Path" Expand-Archive -Path $Zip -DestinationPath $Path -Force Remove-Item $Zip -Force if ($IISWebsite) { Get-ChildItem $Path -Recurse | Unblock-File Start-Website -Name $IISWebsite } if ($IsMacOS -or $IsLinux) { $ServerPath = Join-Path $Path "Universal.Server" /bin/chmod +x $ServerPath } if ($IsLinux) { Write-Verbose "Started PowerShellUniversal service" systemctl start PowerShellUniversal systemctl enable PowerShellUniversal } } } function Uninstall-PSUServer { <# .SYNOPSIS Removes the PowerShell Universal server. .DESCRIPTION Removes the PowerShell Universal server. This is a convenience function that will remove the server for your platform. .PARAMETER Path The path to the PowerShell Universal binaries. If not specified, the path will attempt to be resolved. .EXAMPLE Remove-PSUServer #> [Alias("Remove-PSUServer")] [CmdletBinding(DefaultParameterSetName = "Version")] param( [Parameter()] [string]$Path, [Parameter()] [string]$IISWebsite ) if (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { throw 'You must be an administrator to remove the Universal Server. Please run the command as an administrator.' } if ($IISWebsite -and ($IsLinux -or $IsMacOS)) { throw "IISWebsite is only supported on Windows." } if ($IISWebsite) { Import-Module WebAdministration -ErrorAction Stop } if (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { Write-Verbose "Locating local package with Win32_Product" $Package = Get-CimInstance win32_product -Filter "Name like 'PowerShell Universal%'" | Select-Object -First 1 if ($Package) { Write-Verbose "Removing via msiexec." Start-Process msiexec.exe -ArgumentList "/x $( $Package.LocalPackage ) /quiet /qn /norestart" -Wait } else { throw "Unable to locate PowerShell Universal installation." } } else { if (-not $Path -and -not $IISWebsite) { $ServerPath = Get-Command "Universal.Server" -ErrorAction SilentlyContinue if (-not $ServerPath) { throw "Unable to locate existing PowerShell Universal installation. Use the -Path parameter to specify the folder of the previous installation." } $Path = [System.IO.Path]::GetDirectoryName($ServerPath.Source) } if ($IISWebsite) { $Path = (Get-Website -Name $IISWebsite).PhysicalPath $AppPool = (Get-Website -Name $IISWebsite).ApplicationPool Stop-Website -Name $IISWebsite Remove-Website -Name $IISWebsite Remove-WebAppPool $AppPool Write-Verbose "Removing application files" Remove-Item $Path -Force -Recurse } if ($IsLinux) { Write-Verbose "Stopped PowerShellUniversal service" systemctl stop PowerShellUniversal systemctl disable PowerShellUniversal Remove-Item /etc/systemd/system/PowerShellUniversal.service -Force systemctl daemon-reload Write-Verbose "Removing application files" Remove-Item $Path -Force -Recurse } } } |