Skip to content

Instantly share code, notes, and snippets.

@billdeitrick
Created October 18, 2019 03:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save billdeitrick/d3fa0b7657927768a27c01aaba435e0a to your computer and use it in GitHub Desktop.
Save billdeitrick/d3fa0b7657927768a27c01aaba435e0a to your computer and use it in GitHub Desktop.
An ExamView installation PowerShell script. Demonstrates symlinking data directories in %ProgramFiles(x86)% to user's OneDrive, and a few other workarounds.
# Script Variables
$LOGGING_SUBDIR = "custom_deploy\logs"
# Setup logging environment
## Make directory if it doesn't exist
$log_dir = ($env:ProgramData + "\" + $LOGGING_SUBDIR)
$log_path = ($log_dir + "\examview_install.log")
if (! (Test-Path -Path $log_dir)) {
$result = New-Item -Path $log_dir -ItemType Directory
}
## Define reusable logging function
function Write-CustomLog {
param(
[Parameter(Mandatory=$true)]
[ValidateNotNull()]
[ValidateSet("Debug", "Error", "Info")]
[String]
$Level,
[Parameter(Mandatory=$true)]
[ValidateNotNull()]
[String]
$Message
)
Add-Content -Path $log_path -Value ("$Level >> " + (Get-Date).ToString() + " >> $Message")
}
# Log script start
Write-CustomLog -Level Info -Message "Starting ExamView primary installation script."
# Get profile path for the logged in user (fail install if more than one user logged in)
## Get all owning user names of all running explorer.exe instances
$explorers = (Get-WMIObject -Class Win32_Process -Filter 'Name="explorer.exe"')
$owners = New-Object System.Collections.Generic.HashSet[String]
foreach($instance in $explorers) {
$result = $owners.Add($instance.GetOwner().User)
}
## Fail if more than one user logged in, because we don't know where to point symlinks (who is the primary user?)
if ($owners.Count -ne 1) {
Write-CustomLog -Level Error -Message ("Found " + $owners.Count + " users logged in. Cannot continue; quitting installation.")
exit 1
}
## We have a good username; let's get SID
$username = $owners[0]
$username = $username.Replace('.', '')
$user = New-Object System.Security.Principal.NTAccount("azuread\$username")
$sid = $user.Translate([System.Security.Principal.SecurityIdentifier]).Value
## We have a SID; let's get a profile path
$profile_path = (Get-ChildItem 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList' | Where-Object {$_.Name -like "*$sid"}).GetValue('ProfileImagePath')
## Finally, we know the documents folder path on OneDrive
$od_documents_path = "$profile_path\OneDrive - [Company Name]\Documents"
Write-CustomLog -Level Info -Message "Calculated OneDrive path to use for the installation: '$od_documents_path'"
## Fail if the documents path isn't good
if (!(Test-Path -Path $od_documents_path)) {
Write-CustomLog -Level Error -Message "Calculated OneDrive path is no good. Quitting installation."
exit 1
}
# We know we have a good documents folder path to which we should be able to create a symlink
# for ExamView data. Let's install ExamView and remove superfluous stuff.
Write-CustomLog -Level Info -Message "Running the ExamView installer."
## Silent ExamView Install
Start-Process "$PSScriptRoot\Setup.exe" -Wait -ArgumentList "/S /v/qn"
Write-CustomLog -Level Info -Message "Finished running the ExamView installer."
## Remove TestPlayer Desktop Shortcut (don't think this will ever be used)
Remove-Item -Path "C:\Users\Public\Desktop\ExamView TestPlayer.lnk" -Force
## Uninstall course-specific content bundled with the installer we're using
Start-Process msiexec.exe -Wait -ArgumentList "/x {65345e0b-f58a-490d-aa64-f392ade8219b} /q"
# Setup symlinks for ExamView Data
Write-CustomLog -Level Info -Message "Creating folder SymLinks for ExamView content."
## These are the folders we want
$symlink_folders = @(
"Banks",
"Classes",
"Tests"
)
## Create desired directories if they don't exist
$ev_base_path = "$od_documents_path\ExamView Content"
foreach($folder in $symlink_folders) {
$path = "$ev_base_path\$folder"
if(!(Test-Path -Path $path)) {
Write-CustomLog -Level Info -Message "Creating new path on OneDrive destination (existing path was not found): '$path'"
$result = New-Item -Path $path -ItemType Directory
}
}
## Setup the symlinks
$program_path = (${env:ProgramFiles(x86)} + "\eInstruction\ExamView")
foreach($folder in $symlink_folders) {
Write-CustomLog -Level Info -Message "Creating symlink for folder '$folder'"
# Remove existing folder in %programfiles(x86)%
$result = Remove-Item -Path "$program_path\$folder" -Force -Recurse
# Setup the junction
$result = New-Item -ItemType SymbolicLink -Path "$program_Path\$folder" -Target "$ev_base_path\$folder" -Force
}
Write-CustomLog -Level Info -Message "ExamView primary installation script finished."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment