Universal.psm1
Import-Module "$PSScriptRoot\UniversalDashboard.MaterialUI.psm1" -ErrorAction SilentlyContinue Import-Module "$PSScriptRoot\classes.dll" -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()] param( [Parameter()] [string]$ExecutablePath, [Parameter()] [string]$ListenAddress, [Parameter()] [int]$Port, [Parameter()] [ScriptBlock]$Configuration ) 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()] [Switch]$AddToPath, [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 ($AddToPath) { Write-Warning "-AddToPath is obsolete and will be removed in the next major version." } if ($platform -eq 'win7-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 = "win7-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 } Write-Verbose "Installing server to $Path" if ($LatestVersion) { $Version = (Invoke-WebRequest https://imsreleases.blob.core.windows.net/universal/production/v4-version.txt).Content } Write-Verbose "Downloading version $Version" $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 (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { Write-Verbose "Creating and starting PowerShellUniversal service" New-Service -Name 'PowerShellUniversal' -DisplayName 'PowerShell Universal' -Description 'PowerShell Universal Server' -BinaryPathName "$Path\Universal.Server.exe --service" -StartupType Automatic | Out-Null Get-ChildItem $Path -Recurse | Unblock-File Start-Service -Name 'PowerShellUniversal' Write-Host -ForegroundColor Green 'PowerShell Universal is running on port 5000. View the admin console by visiting http://localhost:5000' } 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) { $PathSeparator = ";" Write-Verbose "Adding $Path to %PATH% variable for the $Scope scope" $envPath = [Environment]::GetEnvironmentVariable('PATH', 'Machine') $newpath = $envPath + $PathSeparator + $Path [Environment]::SetEnvironmentVariable("PATH", $newpath, 'Machine') } 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 ) if ($platform -eq 'win7-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 } $platform = "win7-x64"; if ($PSVersionTable.PSEdition -eq 'Core') { if ($IsLinux) { $platform = "linux-x64" } elseif ($IsMacOS) { $platform = "osx-x64" } } 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 } Write-Verbose "Upgrading server installed at $Path" if ($LatestVersion) { $Version = (Invoke-WebRequest https://imsreleases.blob.core.windows.net/universal/production/v4-version.txt).Content } 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 (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { Write-Verbose "Stopped PowerShellUniversal service" Stop-Service -Name 'PowerShellUniversal' } 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 (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { Get-ChildItem $Path -Recurse | Unblock-File Start-Service -Name 'PowerShellUniversal' Write-Verbose "Started PowerShellUniversal service" } 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 Remove-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 #> [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 (-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 (($PSVersionTable.PSEdition -eq 'Desktop' -or $IsWindows) -and -not $IISWebsite) { Write-Verbose "Stopped PowerShellUniversal service" Stop-Service -Name 'PowerShellUniversal' sc.exe delete "PowerShellUniversal" | Out-Null } 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 } 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 } |