It is currently November 30th, 2022, 6:49 am

Powershell CLI installer for any github-hosted skin

Skins that control functions in Windows or Rainmeter
User avatar
Jax
Posts: 104
Joined: June 7th, 2021, 11:46 am

Powershell CLI installer for any github-hosted skin

Post by Jax »

This script can be ran by using Invoke-WebRequest + Invoke-Expression in Powershell to allow users to install any skins hosted on github even if Rainmeter is not installed.

Setup
---------------------------------
Options:
<OPTION:DEFAULTSKINNAME>: Replace with the default skin that running this script externally would install
<OPTION:YOUR_GITHUB_NAME_OR_ORG>: Replace with your github username or organization, which stores the repositories of your skin

Hosting:
Store this script in any one of your repositories, and make sure that your releases are in .rmskin format

Running script
---------------------------------
To use the installer, run the following command in Powershell, with the <> elements replaced

Code: Select all

Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/<ORG_OR_USER>/<REPO_WHERE_SCRIPT_STORED>/master/Installer.ps1" | Invoke-Expression
To specify which skin from the org / user to install, run the following command in Powershell, with the <> elements replaced

Code: Select all

$installSkin="<ENTER_SKIN_NAME>";Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/<ORG_OR_USER>/<REPO_WHERE_SCRIPT_STORED>/master/Installer.ps1" | Invoke-Expression
How it works
---------------------------------
The script first checks if Rainmeter is installed. If it isn't, it automatically downloads the latest release from Rainmeter's github repo, silently installs it and pre-generate a Rainmeter.ini with all skins hidden. Then, it fetches the latest release from your repository, downloads it and run it.

Try it out!
---------------------------------
The following command installs JaxCore automatically, even with Rainmeter not installed.

Code: Select all

Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/Jax-Core/JaxCore/master/CoreInstaller.ps1" | Invoke-Expression
The script
---------------------------------
Make sure to replace the options with the correct values!

Installer.ps1

Code: Select all

# ----------------------------- Terminal outputs ----------------------------- #
function Write-Part ([string] $Text) {
  Write-Host $Text -NoNewline
}

function Write-Emphasized ([string] $Text) {
  Write-Host $Text -NoNewLine -ForegroundColor "Cyan"
}

function Write-Done {
  Write-Host " > " -NoNewline
  Write-Host "OK" -ForegroundColor "Green"
}

function Write-Info ([string] $Text) {
  Write-Host $Text -ForegroundColor "Yellow"
}

function Write-Red ([string] $Text) {
  Write-Host $Text -ForegroundColor "Red"
}

# -------------------------- Check program installed ------------------------- #

function Check_Program_Installed( $programName ) {
$x86_check = ((Get-ChildItem "HKLM:Software\Microsoft\Windows\CurrentVersion\Uninstall") |
Where-Object { $_."Name" -like "*$programName*" } ).Length -gt 0;
  
if(Test-Path 'HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall')  
{
$x64_check = ((Get-ChildItem "HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall") |
Where-Object { $_."Name" -like "*$programName*" } ).Length -gt 0;
}
return $x86_check -or $x64_check;
}   

# --------------------------------- Download --------------------------------- #
function DownloadFile($url, $targetFile)

{
   $uri = New-Object "System.Uri" "$url"
   $request = [System.Net.HttpWebRequest]::Create($uri)
   $request.set_Timeout(15000) #15 second timeout
   $response = $request.GetResponse()
   $totalLength = [System.Math]::Floor($response.get_ContentLength()/1024)
   $responseStream = $response.GetResponseStream()
   $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create
   $buffer = new-object byte[] 1000KB
   $count = $responseStream.Read($buffer,0,$buffer.length)
   $downloadedBytes = $count
   while ($count -gt 0)
   {
       $targetStream.Write($buffer, 0, $count)
       $count = $responseStream.Read($buffer,0,$buffer.length)
       $downloadedBytes = $downloadedBytes + $count
       Write-Progress -activity "Downloading file '$($url.split('/') | Select -Last 1)'" -status "Downloaded ($([System.Math]::Floor($downloadedBytes/1024))K of $($totalLength)K): " -PercentComplete ((([System.Math]::Floor($downloadedBytes/1024)) / $totalLength)  * 100)
   }
   Write-Progress -activity "Finished downloading file '$($url.split('/') | Select -Last 1)'"
   $targetStream.Flush()
   $targetStream.Close()
   $targetStream.Dispose()
   $responseStream.Dispose()
}

# ---------------------------------- Install --------------------------------- #

function Install-Skin() {
    $api_url = 'https://api.github.com/repos/<OPTION:YOUR_GITHUB_NAME_OR_ORG>/' + $skinName + '/releases'
    $api_object = Invoke-WebRequest -Uri $api_url -UseBasicParsing | ConvertFrom-Json
    $dl_url = $api_object.assets.browser_download_url[0]
    $outpath = "$env:temp\$($skinName)_$($api_object.tag_name[0]).rmskin"
    Write-Part "Downloading    "; Write-Emphasized $dl_url; Write-Part " -> "; Write-Emphasized $outpath
    downloadFile "$dl_url" "$outpath"
    Write-Done
    Write-Part "Running installer   "; Write-Emphasized $outpath
    Start-Process -FilePath $outpath
    If ($Null -NotMatch (get-process "SkinInstaller" -ea SilentlyContinue)) {
        $wshell = New-Object -ComObject wscript.shell
        $wshell.AppActivate('Rainmeter Skin Installer')
        Start-Sleep -s 1.5
        $wshell.SendKeys('{ENTER}')
    }
    Write-Done
    Wait-Process "SkinInstaller"
    $skinFolder = $skinName
    If (Test-Path -Path "$([Environment]::GetFolderPath("MyDocuments"))\Rainmeter\Skins\$skinFolder") {
      Write-Emphasized "`n$skinName is installed successfully. "; Write-Part "Follow the instructions in the pop-up window."
    } else {
      Write-Red "`nFailed to install $skinName! "; Write-Part "Please contact support or try again."
      Return
    }
}

# ----------------------------------- Logic ---------------------------------- #

if ($installSkin) {
    $skinName = $installSkin
} else {
    $skinName = "<OPTION:DEFAULTSKINNAME>"
}

Write-Part "Checking if Rainmeter is installed"

if (Check_Program_Installed("Rainmeter")) {
  Write-Done
  Install-Skin
} else {
  # ----------------------------------- Fetch ---------------------------------- #
  Write-Info "`nRainmeter is not installed, installing Rainmeter"
  $api_url = 'https://api.github.com/repos/rainmeter/rainmeter/releases'
  $api_object = Invoke-WebRequest -Uri $api_url -UseBasicParsing | ConvertFrom-Json
  $dl_url = $api_object.assets.browser_download_url[0]
  $outpath = "$env:temp\RainmeterInstaller.exe"
  # --------------------------------- Download --------------------------------- #
  Write-Part "Downloading    "; Write-Emphasized $dl_url; Write-Part " -> "; Write-Emphasized $outpath
  # Invoke-WebRequest $dl_url -OutFile $outpath
  downloadFile "$dl_url" "$outpath"
  Write-Done
  # ------------------------------------ Run ----------------------------------- #
  Write-Part "Running installer   "; Write-Emphasized $outpath
  Start-Process -FilePath $outpath -ArgumentList "/S /AUTOSTARTUP=1 /RESTART=0" -Wait
  Write-Done
  # ---------------------------- Check if installed ---------------------------- #
  Write-Part "Checking "; Write-Emphasized "$Env:Programfiles\Rainmeter\Rainmeter.exe"; Write-Part " for Rainmeter.exe"
  If (Test-Path -Path "$Env:Programfiles\Rainmeter\Rainmeter.exe") {
    Write-Done
  } else {
    Write-Red "`nFailed to install Rainmeter! "; Write-Part "Make sure you have selected `"Yes`" when installation dialog pops up"
    Return
  }
  # --------------------------------- Generate --------------------------------- #
  Write-Part "Generating "; Write-Emphasized "Rainmeter.ini "; Write-Part "for the first time..."
  New-Item -Path "$env:APPDATA\Rainmeter" -Name "Rainmeter.ini" -ItemType "file" -Force -Value @"
[Rainmeter]
Logging=0
SkinPath=$([Environment]::GetFolderPath("MyDocuments"))\Rainmeter\Skins\
HardwareAcceleration=0

[illustro\Clock]
Active=0
[illustro\Disk]
Active=0
[illustro\System]
Active=0

"@
    Write-Done
    # ---------------------------------- Install --------------------------------- #
    Install-Skin
}