-
Notifications
You must be signed in to change notification settings - Fork 0
/
ChangeDateInstall.ps1
206 lines (174 loc) · 7.03 KB
/
ChangeDateInstall.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#Parent registry path.
$registryParentPath = 'Registry::HKCR\*\shell\'
try {
# Need to do further testing
# Get the ACL for the registry key.
# $registryParentPath = 'Registry::HKCR\*\shell\'
$keyAcl = Get-Acl -LiteralPath $registryParentPath -ErrorAction Stop
# Get username.
$currentUserName = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$userRegistryPermissions = $keyAcl.Access | Where-Object {
$_.IdentityReference.Value -eq $currentUserName -and (
$_.RegistryRights -eq 'FullControl' -or
($_.RegistryRights -eq 'ReadKey' -and $_.RegistryRights -eq 'WriteKey')
)
}
}
catch {
if (-not $userRegistryPermissions) {
Write-Host "The current user does not have read/write permissions on $registryParentPath."
Write-Host "Enter 'i' to ignore this warning or any other key to exit."
$userInput = Read-Host "Input: "
if (-not ($userInput -eq 'i')) {
Write-Host "Closing..."
Exit
}
}
}
# Check if powershell is running as admin.
$userPermissions = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent() `
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $userPermissions) {
# Start a new PowerShell process with the -Verb RunAs flag to request elevation.
do {
# Start a new PowerShell process with the -Verb RunAs flag to request elevation.
Write-Host "The script is not currently running with administrator privileges. Would you like to spawn an admin shell? (Y/n)"
$userInput = Read-Host "Input: "
if ($userInput -eq 'y') {
$curr = Get-Location
$command = "-NoExit -ExecutionPolicy Bypass -Command cd '$curr'; .\ChangeDateInstall.ps1"
Write-Host $command
Start-Process powershell -ArgumentList $command -Verb RunAs
Exit
}
elseif ($userInput -eq 'n') {
Write-Host "Closing..."
Exit
}
else {
Write-Host "Invalid input. Please enter 'y' or 'n'."
}
} while ($true)
}
# Install locations
# Files: C:\Users\%USERNAME%\Documents\Powershell Scripts\ChangeDate
# The parent folder containing this and maybe other scripts.
$rootFolder = Join-Path $env:USERPROFILE 'Documents\Powershell Scripts'
# The folder for this script to install into.
$changeDateInstallFolder = Join-Path $rootFolder 'ChangeDate'
# The locations for the script files to be installed.
$changeDateWrapperInstallLocation = Join-Path $changeDateInstallFolder 'ChangeDateWrapper.vbs'
$changeDateScriptInstallLocation = Join-Path $changeDateInstallFolder 'ChangeDate.ps1'
# The script file local to the installer.
$changeDateScriptResourceLocation = Join-Path (Get-Location) 'ChangeDate.ps1'
# The value for the context menu entry, what will be executed upon click.
$contextMenuRegistryCommand = 'wscript.exe "{0}" "%1"' -f $changeDateWrapperInstallLocation
# Registry: Computer\HKEY_CLASSES_ROOT\*\shell\FixLastWriteDate
$scriptRegistryKeyName = 'FixLastWriteDate'
$changeWriteTimeRegKey = Join-Path $registryParentPath $scriptRegistryKeyName
$changeWriteScriptCommandKey = Join-Path $changeWriteTimeRegKey 'command'
# The registry keys to be created.
$RegKeys = @(
@{
Path = $changeWriteTimeRegKey
Value = "Fix Date"
}
@{
Path = $changeWriteScriptCommandKey
Value = $contextMenuRegistryCommand
}
)
# The folders to be created, used a hash map to challenge myself.
$enviromentFolders = @(
@{
Path = $rootFolder
}
@{
Path = $changeDateInstallFolder
}
)
if (Test-Path -Path $changeDateScriptResourceLocation -PathType Leaf) {
<#
.SYNOPSIS
Copies the PowerShell script to the user's documents and creates a wrapper file.
.DESCRIPTION
Copies the script and creates an additional wrapper (ChangeDateWrapper.vbs) to prevent the PowerShell window from popping up.
.NOTES
All files will be overwritten if this is rerun; the install directories are required.
#>
function Copy-ScriptResources {
$statement = 'Copied file: '
# Wrapper content, used to prevent a PowerShell window from appearing.
$wrapperScriptContent = 'Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "powershell.exe -NoProfile -ExecutionPolicy Bypass -File ""{0}"" -FilePath """ & WScript.Arguments(0) & """", 0, True' -f $changeDateScriptInstallLocation
try {
if (Test-Path -Path $changeDateInstallFolder -PathType Container) {
# Write content to vbs file, in the install folder.
$wrapperScriptContent | Out-File -FilePath $changeDateWrapperInstallLocation -Force
Write-Host "Made wrapper file: $changeDateWrapperInstallLocation `n"
if (-not (Test-Path -Path $changeDateScriptInstallLocation -PathType Leaf)) {
Copy-Item -Path $changeDateScriptResourceLocation -Destination $changeDateScriptInstallLocation -Force
Write-Host "$statement $changeDateScriptResourceLocation `n"
}
}
}
catch {
Write-Host "Error copying/creating scripts: $_"
}
}
<#
.SYNOPSIS
Creates the folders required to install the script.
.DESCRIPTION
Creates folders to provide some organization for customer PowerShell scripts.
.NOTES
The selected installation directory is in the user's documents, this helps with transparency and hopefully encourages learning.
#>
function Initialize-ScriptEnviroment {
$statement = 'Created folder: '
try {
foreach ($Item in $enviromentFolders) {
New-Item -ItemType Directory -Path $Item['Path'] -Force | Out-Null
Write-Host "$statement $($Item['Path']) `n"
}
}
catch {
Write-Host "Error creating script enviroment: $_"
}
}
<#
.SYNOPSIS
Adds the required keys to the registry.
.DESCRIPTION
Creates the keys and values in the registry for the context menu name and the command to execute.
.NOTES
This will only be installed for the administrative user.
#>
function Initialize-RegistryKeys {
$statement = 'Created registry key: '
try {
foreach ($Item in $RegKeys) {
New-Item -Path $Item['Path'] -Value $Item['Value'] -Force | Out-Null
Write-Host "$statement$($Item['Path']) with value: $($Item['Value']) `n"
}
}
catch {
Write-Host "Error creating script enviroment: $_"
}
}
try {
# Setup folders and copy/create resources.
Initialize-ScriptEnviroment
Copy-ScriptResources
# Setup the registry entries.
Initialize-RegistryKeys
Write-Host 'Install completed.'
}
catch {
Write-Host "Error creating registry entry: $_"
}
}
else {
Write-Host 'Installer files missing.'
}