-
Notifications
You must be signed in to change notification settings - Fork 0
/
Detect_VSCode.ps1
198 lines (164 loc) · 7.41 KB
/
Detect_VSCode.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
<#
.DESCRIPTION
Detects if Visual Studio Code is installed on a Windows device using the Windows Package Manager (Winget).
Structure can be adjusted to support any Winget application by changing the WingetAppID variable.
.EXAMPLE
$WingetAppID = "Microsoft.VisualStudioCode"
.\DetectVSCode.ps1
Detects if Visual Studio Code is installed on the device using Winget.
.NOTES
Inspired by John Bryntze; Twitter: @JohnBryntze
.DISCLAIMER
This script is delivered as-is without any guarantees or warranties. Always ensure
you have backups and take necessary precautions when executing scripts, particularly
in production environments.
.LAST MODIFIED
August 7th, 2023
#>
#region Functions
function Find-WingetPath {
<#
.SYNOPSIS
Locates the winget.exe executable within a system.
.DESCRIPTION
Finds the path of the `winget.exe` executable on a Windows system.
Aimed at finding Winget when main script is executed as SYSTEM, but will also work under USER
Windows Package Manager (`winget`) is a command-line tool that facilitates the
installation, upgrade, configuration, and removal of software packages. Identifying the
exact path of `winget.exe` allows for execution (installations) under SYSTEM context.
METHOD
1. Defining Potential Paths:
- Specifies potential locations of `winget.exe`, considering:
- Standard Program Files directory (64-bit systems).
- 32-bit Program Files directory (32-bit applications on 64-bit systems).
- Local application data directory.
- Current user's local application data directory.
- Paths may utilize wildcards (*) for flexible directory naming, e.g., version-specific folder names.
2. Iterating Through Paths:
- Iterates over each potential location.
- Resolves paths containing wildcards to their actual path using `Resolve-Path`.
- For each valid location, uses `Get-ChildItem` to search for `winget.exe`.
3. Returning Results:
- If `winget.exe` is located, returns the full path to the executable.
- If not found in any location, outputs an error message and returns `$null`.
.EXAMPLE
$wingetLocation = Find-WingetPath
if ($wingetLocation) {
Write-Output "Winget found at: $wingetLocation"
} else {
Write-Error "Winget was not found on this system."
}
.NOTES
While this function is designed for robustness, it relies on current naming conventions and
structures used by the Windows Package Manager's installation. Future software updates may
necessitate adjustments to this function.
.DISCLAIMER
This function and script is provided as-is with no warranties or guarantees of any kind.
Always test scripts and tools in a controlled environment before deploying them in a production setting.
This function's design and robustness were enhanced with the assistance of ChatGPT, it's important to recognize that
its guidance, like all automated tools, should be reviewed and tested within the specific context it's being
applied.
#>
# Define possible locations for winget.exe
$possibleLocations = @(
"${env:ProgramFiles}\WindowsApps\Microsoft.DesktopAppInstaller*_x64__8wekyb3d8bbwe\winget.exe",
"${env:ProgramFiles(x86)}\WindowsApps\Microsoft.DesktopAppInstaller*_8wekyb3d8bbwe\winget.exe",
"${env:LOCALAPPDATA}\Microsoft\WindowsApps\winget.exe",
"${env:USERPROFILE}\AppData\Local\Microsoft\WindowsApps\winget.exe"
)
# Iterate through the potential locations and return the path if found
foreach ($location in $possibleLocations) {
try {
# Resolve path if it contains a wildcard
if ($location -like '*`**') {
$resolvedPaths = Resolve-Path $location -ErrorAction SilentlyContinue
# If the path is resolved, update the location for Get-ChildItem
if ($resolvedPaths) {
$location = $resolvedPaths.Path
}
else {
# If path couldn't be resolved, skip to the next iteration
Write-Warning "Couldn't resolve path for: $location"
continue
}
}
# Try to find winget.exe using Get-ChildItem
$items = Get-ChildItem -Path $location -ErrorAction Stop
if ($items) {
Write-Host "Found Winget at: $items"
return $items[0].FullName
break
}
}
catch {
Write-Warning "Couldn't search for winget.exe at: $location"
}
}
Write-Error "Winget wasn't located in any of the specified locations."
return $null
}
#endregion Functions
#region Main
#region Initialization
$wingetPath = "" # Path to Winget executable
$detectSummary = "" # Script execution summary
$result = 0 # Exit result (default to 0)
$WingetAppID = "Microsoft.VisualStudioCode" # Winget Application ID
$processResult = $null # Winget process result
$exitCode = $null # Software installation exit code
$installInfo # Information about the Winget installation process
#endregion Initialization
# Make the log easier to read
Write-Host `n`n
# Check if Winget is available in current context, if not, find it
$wingetPath = (Get-Command -Name winget -ErrorAction SilentlyContinue).Source
if (-not $wingetPath) {
Write-Host "Winget not detected, attempting to locate in system..."
$wingetPath = Find-WingetPath
}
if (-not $wingetPath) {
Write-Host "Winget (Windows Package Manager) is absent on this device."
$detectSummary += "Winget NOT detected. "
$result = 5
} else {
$detectSummary += "Winget located at $wingetPath. "
}
# Use Winget to detect if the Visual Studio Code is installed
if ($result -eq 0) {
try {
$tempFile = New-TemporaryFile
Write-Host "Detecting App $WingetAppID installation"
$processResult = Start-Process -FilePath "$wingetPath" -ArgumentList "list -e --id ""$WingetAppID"" --accept-source-agreements" -NoNewWindow -Wait -RedirectStandardOutput $tempFile.FullName -PassThru
$exitCode = $processResult.ExitCode
$installInfo = Get-Content $tempFile.FullName
Remove-Item $tempFile.FullName
Write-Host "Winget detection exit code: $exitCode"
if ($exitCode -eq 0) {
Write-Host "$WingetAppID is installed on this device."
$detectSummary += "$WingetAppID is installed. "
$result = 0
} else {
$detectSummary += "Error during detection, exit code: $exitCode. "
$result = 1
}
}
catch {
Write-Host "Encountered error during detection: $_"
$detectSummary += "Detection failed with exit code $($processResult.ExitCode). "
$result = 1
}
}
# Simplify reading in Log
Write-Host `n`n
# Output the final results
if ($result -eq 0) {
Write-Host "OK $([datetime]::Now) : $detectSummary"
Exit 0
} elseif ($result -eq 1) {
Write-Host "FAIL $([datetime]::Now) : $detectSummary"
Exit 1
} else {
Write-Host "NOTE $([datetime]::Now) : $detectSummary"
Exit 0
}
#endregion Main