greatDismal.psm1
function Get-Despair{ param ( [string[]]$adjectives = @(), [string[]]$nouns = @(), [string]$dismalFolder = (join-path $env:APPDATA "\great dismal\"), [string]$logfile = (join-path $dismalFolder "log.txt"), [int]$safeSearch = 0, [string[]]$newNouns, [switch]$lastPic, [switch]$showLog, [switch]$noLog, [switch]$install, [switch]$uninstall, [switch]$listAdjectives, [switch]$listNouns, [switch]$listTerms, [switch]$checkForUpdates, [string[]]$newAdjectives, [switch]$setTerms, [switch]$help ) $v = "1.0.22" write-host "Great Dismal version $v logfile at $logfile" $lastUpdate = $false; $shouldUpdate = $false; if (test-path $logfile){ $lastUpdate = (Get-Content $logfile) | Where-Object {$_ -match "([^-]*)->\s*updating"} if ($lastUpdate){ # check every week, future versions might slow this down a bit $shouldUpdate = (get-date $Matches[1]) -lt ((get-date).AddDays(-7)) } else { $shouldUpdate = $true; } } if ($shouldUpdate) { write-GDLog "updating GD" -logfile $logfile Update-module "GreatDismal" } # do the stuffs # installation hoo-hah if (! (test-path $dismalFolder)){mkdir $dismalFolder} $dismalPic = Join-Path $dismalFolder "greatDismal.jpg" if ($install){ install-GreatDismal -adjectives $adjectives -nouns $nouns -dismalFolder $dismalFolder -scriptPath $scriptPath -logfile $logfile -nolog $nolog -safeSearch $safeSearch -version $v } if ($lastPic) { #user wants to see the current pic Invoke-Item $dismalPic } if ($showLog){ #user wants to see the log Get-Content $logfile } if ($uninstall){ #user wants to see the log uninstall-GreatDismal -logfile $logfile -dismalFolder $dismalFolder; } if ($listAdjectives -or $listNouns -or $listTerms){ #user wants to see the words if ($listAdjectives -or $listTerms) {write-DismalsearchTerms -adjectives} if ($listNouns -or $listTerms) {write-DismalsearchTerms -nouns} } if ($newAdjectives.length -or $newNouns.length){ add-DismalSearchTerm -adjectives $newAdjectives -nouns $newNouns -logfile $logfile } if ($setTerms){ if (! ($adjectives.length -gt 0 -and $nouns.length -gt 0)){ write-host "You need to specify an array of words for -adjectives and -nouns" -ForegroundColor Red } else { set-dismalSearchTerms -adjectives $adjectives -nouns $nouns -logfile $logfile } } if ($help){ write-host "Great Dismal gets pictures of despair and gloom for your lock screen.`nInstall using " -ForegroundColor "yellow" -NoNewline write-host "Get-Despair -install" -ForegroundColor "white" write-host "Note that you must be an admin user to install it. Soz." -ForegroundColor "yellow" write-host "You can edit the " -ForegroundColor "yellow" -NoNewline write-host "nouns.dat " -ForegroundColor "white" -NoNewline write-host "and " -ForegroundColor "yellow" -NoNewline write-host "adjectives.dat " -ForegroundColor "white" -NoNewline write-host "files to use whatever search terms you like, you weirdo" -ForegroundColor "yellow" -NoNewline } # only do the things if the user hasn't specified anything else if (!($install -or $lastPic -or $showLog -or $uninstall -or $listAdjectives -or $listNouns -or $listTerms -or $newAdjectives.length -or $newNouns.length -or $setTerms -or $help)){ #get the pic and set the screen get-dismalpicFortheDay -adjectives $adjectives -nouns $nouns -dismalPic $dismalPic -logFile $logfile -nolog $nolog -safeSearch $safeSearch; } } function get-dismalpicFortheDay { param ( [string[]]$adjectives = @(), [string[]]$nouns = @(), [string]$dismalPic, [string]$logfile, [bool]$nolog, [int]$safeSearch = 0 ) Write-Host "getting some fresh despair for you" $key = "48efbaf66f9bf4b1bf2d0b04c46b02b1" $scrt = "9f5ab5c8abc77684" if ($adjectives.Length -eq 0){ $adjectives = get-dismalAdjectives -logfile $logfile } if ($nouns.Length -eq 0){ $nouns = get-dismalNouns -logfile $logfile } $attempts = 0; if ($safeSearch -gt 0){ $safeSearchStr = "&safe_search="+$safeSearch } else { $safeSearchStr = "" } while ((! $photogURL) -and ($attempts -lt 64)){ $picfortheday = @($adjectives[(Get-Random($adjectives.Length))], $nouns[(Get-Random($nouns.Length))]) -join ","; $result = Invoke-RestMethod -URi ("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key={0}&secret={1}&tags={2}&tag_mode=all&sort=interestingness-desc&media=photos&format=rest&extras=url_k{3}" -f $key, $scrt, $picfortheday, $safeSearchStr) -Method Get $pics = $result.rsp.photos.photo; if ($pics.length -gt 0){ write-GDLog ("looking for pics of {0}, found {1}" -f ($picfortheday.replace(",", " and ")), $pics.length) -logFile $logfile -nolog $nolog $randompics = 0; while (($null -eq $photogURL) -and ($randompics -lt $pics.length) ){ $randoPhoto = Get-Random $pics.Length; $photogURL = $pics[$randoPhoto].url_k; $randompics++ } if ($null -ne $photogURL){ write-GDLog ("found a photo at {0}" -f $photogURL) -logFile $logfile -nolog $nolog } else { write-GDLog ("no url found. Trying another search") -logFile $logfile -nolog $nolog } $photoTitle = $pics[$randoPhoto].title; } else { write-GDLog ("{0} - didn't find any pics of {1}" -f (get-date), ($picfortheday.replace(",", " and "))) -logFile $logfile -nolog $nolog } $attempts++; } (New-Object Net.webclient).DownloadFile($photogURL, $dismalPic) write-GDLog ("downloaded `"{0}`"" -f $photoTitle) -logFile $logfile -nolog $nolog Set-LockscreenWallpaper -LockScreenImageValue $dismalPic -logfile $logfile; } function Set-LockscreenWallpaper { # this was adapted from # https://abcdeployment.wordpress.com/2017/04/20/how-to-set-custom-backgrounds-for-desktop-and-lockscreen-in-windows-10-creators-update-v1703-with-powershell/ # The Script sets custom background Images for the Lock Screen by leveraging the new feature of PersonalizationCSP that is only available in # the Windows 10 v1703 aka Creators Update and later build versions # # Applicable only for Windows 10 v1703 and later build versions # param( [string]$LockScreenImageValue, [string]$logfile ) $RegKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP" $LockScreenPath = "LockScreenImagePath" $LockScreenStatus = "LockScreenImageStatus" $LockScreenUrl = "LockScreenImageUrl" $StatusValue = "1" If (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")){ IF(!(Test-Path $RegKeyPath)) { New-Item -Path $RegKeyPath -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenStatus -Value $StatusValue -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenPath -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenUrl -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null } ELSE { New-ItemProperty -Path $RegKeyPath -Name $LockScreenStatus -Value $value -PropertyType DWORD -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenPath -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null New-ItemProperty -Path $RegKeyPath -Name $LockScreenUrl -Value $LockScreenImageValue -PropertyType STRING -Force | Out-Null } } else { write-GDLog ("Error: not running as Admin, can't set the registry.") -logFile $logfile -nolog $nolog } } function install-GreatDismal { param( [String]$logfile = (join-path $env:APPDATA "\great dismal\log.txt"), [string]$dismalFolder = (join-path $env:APPDATA "\great dismal\"), [int]$safeSearch = 0, [string[]]$adjectives = @(), [string[]]$nouns = @(), [bool]$nolog, [bool]$phoneHome, [string]$version ) #if we're running pwsh using "powershell" in the scheduled task will fail, because the module won't be found $PSVers = (get-host).version.Major if ($PSVers -ge 6){ $PSCmd = "pwsh.exe" } else { $PSCmd = "powershell.exe" } # check to see if user is admin if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")){ # is admin, we're good to install $divider = "`n" + ("-" * (Get-Host).ui.rawui.windowsize.width) + "`n"; # trick to make a row of dashes the width of the window write-host ($divider) -foregroundColor "yellow" Write-Host "This will install GreatDismal on your machine and it will download a random dismal login screen every time you log in" -ForegroundColor DarkYellow Write-Host "Note that the contents of the pictures are beyond the control of the developer, and may be " -NoNewline -ForegroundColor DarkYellow Write-Host "unsafe for work." -ForegroundColor Red write-host ($divider) -foregroundColor "yellow" # define the workstation unlock as the trigger $stateChangeTrigger = Get-CimClass -Namespace ROOT\Microsoft\Windows\TaskScheduler -ClassName MSFT_TaskSessionStateChangeTrigger $trigger = New-CimInstance -CimClass $stateChangeTrigger -Property @{ StateChange = 8 # TASK_SESSION_STATE_CHANGE_TYPE.TASK_SESSION_UNLOCK (taskschd.h) } -ClientOnly # Create a task scheduler event $argument = "-WindowStyle Hidden -command `"import-module 'GreatDismal'; get-Despair -logfile '{0}' -dismalFolder '{1}'{2}{3}{4}{5}`"" -f ` $logfile, ` $dismalFolder, ` $(if ($adjectives.Length -gt 0){" -adjectives ({0})" -f ($adjectives -join ", ")} else {""}), ` $(if ($nouns.Length -gt 0){" -nouns ({0})" -f ($nouns -join ", ")} else {""}), ` $(if ($phoneHome){" -checkForUpdates"} else {""}), ` $(if ($safeSearch -gt 0){" -safeSearch " + $safeSearch} else {""}) $action = New-ScheduledTaskAction -id "GreatDismal" -execute $PSCmd -Argument $argument $settings = New-ScheduledTaskSettingsSet -Hidden -StartWhenAvailable -RunOnlyIfNetworkAvailable Write-Host "for this script to work it needs elevated privileges" -ForegroundColor Blue Write-Host "use Domain\User if you're on a domain." $Credential = Test-Credential if ($Credential){ # actually install the shiz Write-Host "Username checks out." -ForegroundColor Green write-GDLog "Unregistering existing scheduled task." -logfile $logfile -nolog $nolog Write-Host "hit Y to delete old version of Great Dismal when asked." -ForegroundColor Blue Unregister-ScheduledTask -TaskName "greatDismal" -ErrorAction SilentlyContinue Register-ScheduledTask ` -TaskName "greatDismal" ` -User $Credential.username ` -Action $action ` -Settings $settings ` -Description 'Regular doses of gloom on your lockscreen'` -Trigger $trigger -RunLevel Highest ` -Password $Credential.GetNetworkCredential().Password ` -taskPath "\pureandapplied\" } if ($? -and (Get-ScheduledTask -TaskName "GreatDismal" -ErrorAction SilentlyContinue)){ write-GDLog "GreatDismal version $version is installed" -colour "Green" -logFile $logfile -nolog $nolog } else { throw "Bollocks. Something went wrong. Computers suck." } } else { # not admin Write-Host "You need run this script as an Admin to install it" -BackgroundColor Red -ForegroundColor Yellow throw "Computer says no." } } function uninstall-GreatDismal { param( [string]$logfile, [string]$dismalFolder ) if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")){ $RegKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\PersonalizationCSP" remove-item -Path $RegKeyPath -Force -Recurse| Out-Null; Unregister-ScheduledTask -TaskName "greatDismal" -ErrorAction SilentlyContinue; Remove-Item $dismalFolder -Recurse -ErrorAction SilentlyContinue; $scriptPath = (get-item $myInvocation.ScriptName).Directory # remove-module doesn't seem to work for psgallery modules. So we do it manually # just check that we're actually removing the greatdismal folder if ($scriptPath.name -eq "GreatDismal"){ Write-host "You have to manually remove the module now. Just delete the GreatDismal folder." -BackgroundColor Yellow -ForegroundColor Red Invoke-Item $scriptPath; #open the folder containing the module folder (usually ~\Documents\WindowsPowershell\Modules) } } else { Write-host "you need to run this script as admin to uninstall it" -BackgroundColor Red -ForegroundColor Yellow throw "Computer says no." } } function Test-Credential { # check password, allowing multiple attemps $againWithThePassword = $true; $usernameChecksOut = $false; Add-Type -AssemblyName System.DirectoryServices.AccountManagement $DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext('machine',$env:COMPUTERNAME) while ((! $usernameChecksOut) -and $againWithThePassword){ $Credential = Get-Credential -ErrorAction SilentlyContinue if ($null -eq $Credential){ Write-Warning "You didn't give me any credentials. I can't help you if you won't help me." $againWithThePassword = ((read-host "Again with the password? Y/n").ToLower() -ne "n") } else { $usernameChecksOut = $DS.ValidateCredentials($Credential.UserName, $Credential.GetNetworkCredential().Password) if ($usernameChecksOut){ return $Credential } else { Write-Warning "Username and / or password is incorrect. Soz."; $againWithThePassword = ((read-host "Again with the password? Y/n").ToLower() -eq "n") } } if (! $againWithThePassword){ return $false } Start-Sleep 1 } } function write-GDLog { param ( [string]$Msg, [string]$colour = "White", [string]$logfile, [bool]$nolog ) if ((-not $nolog) -and ($null -ne $logfile)){ $date = Get-date -f "dd/MM/yyyy HH:mm:ss" if (! (test-path $logfile )){set-content $logfile "The Great Dismal Log"} # trim the log if it gets too long 64k is long enough right? if ((get-item $logfile).length -gt 64kb){ # get the last 20 lines $oldlog = (Get-Content $logfile)[-20..-1] # carry over the last update check $lastUpdate = "" $lastUpdate = (Get-Content $logfile) | Where-Object {$_ -match "([^-]*)->\s*UpdateCheck"} if ($lastUpdate){$lastUpdate = $lastUpdate[-1]} Set-Content $logfile ("The Great Dismal Log`n" + $date + "-> " + "Trimmed log") Add-Content $logfile $oldlog Add-Content $logfile $lastUpdate } add-content $logfile ("" + $date + "-> " + $msg) } Write-Host $Msg -foregroundColor $colour } function get-dismalAdjectives { param ( [string]$adPath = (Join-Path $PSScriptRoot "adjectives.dat"), [string]$logfile ) $adjectives = (Get-Content $adPath).split(";") if ($adjectives.length -eq 0){ $adjectives = "dismal" write-GDLog "No adjectives found!" -colour "Red" -logfile $logfile } return ($adjectives|Sort-Object) } function get-dismalNouns { param ( [string]$nounPath = (Join-Path $PSScriptRoot "nouns.dat") , [string]$logfile ) $nouns = (Get-Content $nounPath).split(";") if ($nouns.length -eq 0){ $nouns = "dismal" write-GDLog "No nouns found!" -colour "Red" -logfile $logfile } return ($nouns|Sort-Object) } function write-DismalsearchTerms{ param( [switch]$adjectives, [switch]$nouns, [string]$logfile ) if (! ($adjectives -or $nouns)){$adjectives = $nouns = $true} if ($adjectives){ $adjectiveList = get-dismalAdjectives -logfile $logfile Write-Host $adjectiveList } if ($nouns){ $nounList = get-dismalnouns -logfile $logfile Write-Host $nounList } } function set-dismalSearchTerms{ param( [string[]]$adjectives, [string[]]$nouns ) Set-Content (Join-Path $PSScriptRoot "adjectives.dat") ($gdAdjectives -join ";") Set-Content (Join-Path $PSScriptRoot "nouns.dat") ($gdNouns -join ";") } function add-DismalSearchTerm { param ( [string[]]$adjectives, [string[]]$nouns, [string]$logfile ) $gdAdjectives = get-dismalAdjectives -logfile $logfile if ($adjectives.length -gt 0){ $adjectives|ForEach-Object{ if(!($gdAdjectives.Contains($_))){ $gdAdjectives += $_ write-GDLog "Added $_ to adjectives" -colour "Green" -logfile $logfile } } } $gdNouns = get-dismalNouns -logfile $logfile if ($nouns.length -gt 0){ $nouns|ForEach-Object{ if(!($gdNouns.Contains($_))){ $gdNouns += $_ write-GDLog "Added $_ to nouns" -colour "Green" -logfile $logfile } } } set-dismalSearchTerms -adjectives $gdAdjectives -nouns $gdNouns } |