Created
February 19, 2020 23:27
-
-
Save TimCurwick/8e7ad3f98731def6beb313a6073f83b1 to your computer and use it in GitHub Desktop.
Publish-MadUDDashboard - Enhanced and tweaked version of Publish-UDDashboard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Publish-SSAUDDashboard | |
{ | |
<# | |
.SYNOPSIS | |
Publish Universal Dashboard dashboard as a service. | |
Enhanced version of UD module command Publish-UDDashboard | |
.PARAMETER DisplayName | |
Display name of the service. | |
Required | |
.PARAMETER ServiceName | |
Name of the service. | |
Non-standard characters will be removed. | |
Optional | |
Defaults to the DisplayName (minus any non-standard characters) | |
.PARAMETER Description | |
Description of the service. | |
Optional | |
Defaults to "PowerShell Universal Dashboard $DisplayName" | |
.PARAMETER StartupType | |
Startup type of the service | |
Options | |
Auto | |
Demand (i.e. - Manual) | |
Disabled | |
Delayed-Auto | |
Optional | |
Defaults to Auto | |
.PARAMETER DashboardFile | |
Full or relative path of the dashboard script file to use. | |
If Dashboard file is not named "Dashboard.ps1" it will be copied to | |
"Dashboard.ps1" | |
Required | |
.PARAMETER TargetPath | |
Full or relative path and name of the folder to use for the service. | |
UniversalDashboard module files will be copied into TargetPath. | |
Optional | |
Defaults to present location of DashboardFile | |
.PARAMETER UDVersion | |
Version of UniversalDashboard module to use. | |
Optional | |
Defaults to latest installed version | |
.PARAMETER Credential | |
PSCredential to use as service account for the service. | |
Optional | |
Defaults to SYSTEM | |
.PARAMETER Start | |
Switch parameter | |
If -Start is present... | |
The new service is started | |
If -Start is not present (default)... | |
The new service is not started | |
.PARAMETER Force | |
Switch parameter | |
If -Force is present... | |
Any existing service with the same ServiceName will be overwritten. | |
If -Force is not present (default)... | |
An existing service with the same ServiceName will cause an error. | |
.NOTES | |
Dependencies | |
Module | |
UniversalDashboard | |
Requires permissions to create, modify, (and somtimes delete, | |
start, and stop) Windows services (usually done by running as a | |
local administrator) | |
Folder | |
Write permissions on TargetFolder | |
Files | |
Read permissions on DashboardFile | |
v 1.0 2020/ 2/19 Tim Curwick Created (Modified and enhanced version of UniversalDashboard command) | |
#> | |
[CmdletBinding()] | |
param( | |
[parameter( Mandatory )] | |
[string]$DisplayName, | |
[string]$ServiceName, | |
[string]$Description, | |
[ValidateSet( 'Auto', 'Demand', 'Disabled', 'Delayed-Auto' )] | |
[string]$StartupType = 'Auto', | |
[parameter( Mandatory )] | |
[string]$DashboardFile, | |
[string]$TargetPath, | |
[version]$UDVersion, | |
[pscredential]$Credential, | |
[switch]$Start, | |
[switch]$Force ) | |
try | |
{ | |
# Override ErrorActionPreference for error handling | |
$EAP = $ErrorActionPreference | |
$ErrorActionPreference = 'Stop' | |
# Get Dashboard file object | |
# (Will throw error if not found) | |
$Dashboard = Get-Item -Path $DashboardFile | |
# If DashboardFile was "found" but is a directory | |
# Throw error | |
If ( $Dashboard.PSIsContainer ) | |
{ | |
throw [System.IO.FileNotFoundException]'Unable to find the specified DashboardFile.' | |
} | |
# Set default value of ServiceName, as needed | |
If ( -not $ServiceName ) | |
{ | |
$ServiceName = $DisplayName | |
} | |
# Sanitize invalid characters from service name | |
# (Well, technically, most characters are allowed, but are not customarily used. | |
# I'm restricting you to a short list of commonly used characters.) | |
$ServiceName = $ServiceName -replace '[^()\-_\.0-9A-Za-z]+', '' | |
# Set default value of Description, as needed | |
If ( -not $Description ) | |
{ | |
$Description = "PowerShell Universal Dashboard $DisplayName" | |
} | |
# Set default value of TargetPath to dashboard location, as needed | |
If ( -not $TargetPath ) | |
{ | |
$TargetPath = $Dashboard.DirectoryName | |
} | |
# If UDVersion specified | |
# Get specified version of UniversalDashboard module | |
If ( $UDVersion ) | |
{ | |
# Add zeros as needed UDVersion | |
# (Because 2.7 does not equal 2.7.0) | |
While ( $UDVersion.Build -lt 0 ) | |
{ | |
$UDVersion = [version]( $UDVersion.ToString() + '.0' ) | |
} | |
# Get specified version of UniversalDashboard | |
$Module = $Null | |
$Module = Get-Module -Name UniversalDashboard -ListAvailable | | |
Where-Object Version -eq $UDVersion | | |
Select-Object -First 1 | |
# If specified module not found | |
# Throw error | |
If ( -not $Module ) | |
{ | |
throw [System.IO.FileNotFoundException]"UniversalDashboard module version `"$UDVersion`" not found." | |
} | |
} | |
# Else (UDVersion not specified) | |
# Get UniversalDashboard module | |
Else | |
{ | |
# Get imported UniversalDashboard module | |
$Module = Get-Module -Name UniversalDashboard | |
# If not imported | |
# Get most recent installed version of UniversalDashboard module | |
If ( -not $Module ) | |
{ | |
$Module = Get-Module -Name UniversalDashboard -ListAvailable | | |
Sort-Object -Property Version -Descending | | |
Select-Object -First 1 | |
} | |
# If Universal Dashboard module not found | |
# Throw error | |
If ( -not $Module ) | |
{ | |
throw [System.IO.FileNotFoundException]'UniversalDashboard module not found.' | |
} | |
} | |
# Get existing service, if any | |
$ExistingService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue | |
# If ServiceName already exists and Force was not specified | |
# Throw error | |
If ( $ExistingService -and -not $Force ) | |
{ | |
throw "A service named `"$ServiceName`" already exists. Use -Force to overwrite existing service." | |
} | |
# Stop existing service, if any, as needed | |
If ( $ExistingService ) | |
{ | |
# Capture "before" statuts | |
$ExistingServiceStatus = [string]$ExistingService.Status | |
# Stop existing service, as needed | |
If ( $ExistingService.CanStop ) | |
{ | |
try | |
{ | |
# Stop existing service | |
# Wait up to 30 seconds | |
$ExistingService.Stop() | |
$ExistingService.WaitForStatus( 'Stopped', [timespan]'00:00:30' ) | |
# Give it another couple seconds or we get file lock issues | |
Start-Sleep -Seconds 2 | |
} | |
catch {} | |
# Set flag (for possible cleanup later) | |
$ExistingServiceStopped = $True | |
} | |
Else | |
{ | |
# Set flag | |
$ExistingServiceStopped = $False | |
} | |
} | |
try | |
{ | |
# Create directory TargetPath, as needed | |
If ( -not $( try { Test-Path -Path $TargetPath } catch {} ) ) | |
{ | |
$Null = New-Item $TargetPath -Type Directory | |
} | |
# Derive UniversalDashboard module path | |
$ModulePath = Split-Path -Path $Module.Path | |
# Copy UniversalDashboard to TargetPath | |
# (Skip file Dashboard.ps1, if any, to avoid overwriting DashboardFile) | |
Get-ChildItem -Path $ModulePath -Exclude Dashboard.ps1 | | |
Copy-Item -Destination $TargetPath -Recurse -Force | |
# Copy DashboardFile to TargetPath and name, as needed | |
If ( $Dashboard.Name -ne 'Dashboard.ps1' -or $Dashboard.DirectoryName -ne $TargetPath ) | |
{ | |
$TargetDashboardFile = Join-Path -Path $TargetPath -ChildPath 'Dashboard.ps1' | |
Copy-Item -Path $Dashboard.FullName -Destination $TargetDashboardFile -Force | |
} | |
} | |
# Error copying files to TargetPath | |
# Turn existing service, if any, back on, if needed | |
# Rethrow error | |
catch | |
{ | |
try | |
{ | |
# If we previously stopped the existing service | |
# Start it | |
If ( $ExistingService -and $ExistingServiceStatus -eq 'Running' -and $ExistingServiceStopped ) | |
{ | |
# Start existing service | |
# Wait up to 10 seconds | |
$ExistingService.Start() | |
$ExistingService.WaitForStatus( 'Running', [timespan]'00:00:10' ) | |
} | |
} | |
catch {} | |
throw $_ | |
} | |
try | |
{ | |
# If ExistingService | |
# Delete it | |
If ( $ExistingService ) | |
{ | |
$Step = "Deleting existing service `"$ServiceName`"." | |
# Delete existing service | |
$Result = sc.exe delete $ServiceName | |
# If result is not Success | |
# Throw error | |
If ( -not ( $Result -like '*Success*' ) ) | |
{ | |
throw ( $Result -join ' ' ) | |
} | |
} | |
$Step = "Creating service ServiceName `"$ServiceName`" DisplayName `"$BinPath`" BinPath `"$BinPath`" StartType `"$StartupType`"." | |
# Build path to service executable | |
$BinPath = [System.IO.Path]::Combine( $TargetPath, 'net472', 'UniversalDashboard.Server.exe' ) | |
# Create service | |
$Result = sc.exe create $ServiceName DisplayName= "$DisplayName" binPath= "$BinPath --run-as-service" start= "$StartupType" | |
# If result is not Success | |
# Throw error | |
If ( -not ( $Result -like '*Success*' ) ) | |
{ | |
throw ( $Result -join ' ' ) | |
} | |
$Step = "Setting service ServiceName `"$ServiceName`" Description `"$Description`"." | |
# Set description | |
$Result = sc.exe description $ServiceName "$Description" | |
# If result is not Success | |
# Throw error | |
If ( -not ( $Result -like '*Success*' ) ) | |
{ | |
throw ( $Result -join ' ' ) | |
} | |
# If Credential specified | |
# Set service credential | |
If ( $Credential ) | |
{ | |
$Step = "Setting service Credential, user name `"$($Credential.UserName)`"." | |
# Set service credential | |
$Result = ( Get-WmiObject -ClassName win32_service -Filter "name='$ServiceName'" ). | |
Change( $Null, $Null, $Null, $Null, $Null, $Null, $Credential.UserName, $Credential.GetNetworkCredential().Password, $Null, $Null, $Null ) | |
# If result has a non-zero return code | |
# Throw error | |
If ( $Result -match 'ReturnValue.+[1-9]' ) | |
{ | |
throw | |
} | |
} | |
# If Start specified | |
# Start service | |
If ( $Start ) | |
{ | |
$Step = "Starting service ServiceName `"$ServiceName`"." | |
# Set service credential | |
$Result = sc.exe start $ServiceName | |
# If result is not Success | |
# Throw error | |
If ( $Result -like '*Fail*' ) | |
{ | |
throw ( $Result -join ' ' ) | |
} | |
} | |
} | |
catch | |
{ | |
throw ( "Error: $Step $($_.Exception.Message)" ) | |
} | |
} | |
# Clean up | |
finally | |
{ | |
$ErrorActionPreference = $EAP | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment