Create-IntuneRemediation.ps1
<#PSScriptInfo
.VERSION 1.0.1 .GUID 3b2966d1-96be-4da2-99fe-485984dd14a4 .AUTHOR Jeff Gilbert .COMPANYNAME .COPYRIGHT .TAGS Intune .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Version 1.0: Original published version. #> <# .DESCRIPTION This script creates a Visual Studio Code workspace for Intune remediation scripts. It sets up the necessary folders, tasks, and scripts for creating and managing detection and remediation scripts. If you don't have Visual Studio Code installed, it will prompt you to download VS Code Portable. .PARAMETER outDir The output directory where the workspace and files will be created. Default location is My Documents\IntuneRemediations. .PARAMETER workSpaceName The name of the workspace to be created. Default is "MyRemediation". .EXAMPLE .\IntuneRemediationSetup.ps1 -outDir "IntuneRemediations" -workSpaceName "MyRemediation" Creates a workspace named "MyRemediation" in the "Documents\IntuneRemediations" directory. .NOTES For best results, run this script in a PowerShell terminal with administrative privileges. Ensure that the required tools and dependencies are installed and available in the system PATH. A scratch directory will be created in the specified output directory for storing test files. #> param ( [Parameter(Mandatory=$false)] [string]$workSpaceName = "MyRemediation", [Parameter(Mandatory=$false)] [string]$outDir = "IntuneRemediations" ) Clear-Host $myDocs = [Environment]::GetFolderPath("MyDocuments") $outDir = Join-Path $myDocs $outDir $path = Join-Path $outDir $workSpaceName if (-not (Test-Path -Path $path)) { New-Item -Path $path -ItemType Directory | Out-Null } else { $rand = Get-Random -Minimum 1 -Maximum 100 $workSpaceName = $workSpaceName + "-" + $rand $path = Join-Path $outDir $workSpaceName } # Create the scripts and scratch folders New-Item -ItemType Directory -Path $path\scripts | Out-Null New-Item -ItemType Directory -Path $path\scratch | Out-Null # Define the folders to include in the workspace $folders = @( @{ path = $path } ) # Define workspace settings (optional) $settings = @{ "editor.tabSize" = 4 "files.exclude" = @{ "*.code-workspace" = $true ".vscode" = $true ".git" = $true } } $tasks = @{ version = "2.0.0" tasks = @( @{ label = "Generate example file" type = "shell" command = "./.vscode/makeExample.ps1" problemMatcher = "[]" } ) } # Create the workspace JSON structure $workspace = @{ folders = $folders settings = $settings tasks = $tasks } # Convert the workspace structure to JSON $workspaceJson = $workspace | ConvertTo-Json -Depth 10 -Compress # Write the JSON to the .code-workspace file Write-Output "Creating $workSpaceName workspace file..." $workspaceFilePath = Join-Path $path "$workSpaceName.code-workspace" Set-Content -Path $workspaceFilePath -Value $workspaceJson -Encoding UTF8 | Out-Null Write-Host " $workSpaceName.code-workspace created at $outDir" # Put shortcut in outdir $WshShell = New-Object -ComObject WScript.Shell $Shortcut = $WshShell.CreateShortcut("$outDir\$workSpaceName.lnk") $Shortcut.TargetPath = "$workspaceFilePath" $Shortcut.Save() $taskFolderPath = Join-Path $path ".vscode" # Ensure the .vscode folder exists if (-not (Test-Path -Path $taskFolderPath)) { New-Item -ItemType Directory -Path $taskFolderPath | Out-Null $hide = Get-Item $taskFolderPath -Force $hide.attributes = 'Hidden' } # -------------------------------------------- Create the detection.ps1 file ------------------------------------------- $detectionScript = @" <# .SYNOPSIS .DESCRIPTION .PARAMETER .EXAMPLE .NOTES #> #-------------------------------------------------------- Functions --------------------------------------------------------- #------------------------------------------------------- Begin Script ------------------------------------------------------- <# No logging performed by default for detection scripts, as they do not make changes to the device. Use write-host or write-output to display messages in the Intune portal's device status for your remediation. #> try { # Your script logic goes here. `$someCondition -eq "xyz" # This is just a placeholder for something you're checking for in your detection logic #----- Test if a specific condition is met ----- if (`$someCondition -eq `$false) { Write-Output "No issues detected." Exit 0 # Detection: compliant }Else { Write-Output "Issues detected." Exit 1 # Detection: non-compliant } } catch { # Do this if a terminating exception happens Write-Error "An error occurred: $_" } # Stop-Transcript Exit "@ $detectionScript | Out-File -FilePath $path\scripts\$workSpaceName"_detection.ps1" -Encoding UTF8 -Force Write-Output " Default detection script created" # -------------------------------------------- Create the remediation.ps1 file ------------------------------------------- $remediationScript = @" <# .SYNOPSIS .DESCRIPTION .PARAMETER .EXAMPLE .NOTES #> #-------------------------------------------------------- Functions --------------------------------------------------------- #------------------------------------------------------- Begin Script ------------------------------------------------------- # Logging optional for remediations because the script output is displayed in the Intune portal's device status for your remediation. # Logging enabled in this example where Intune can grab it if needed. `$logDir = "`$(`$env:ProgramData)\Microsoft\IntuneManagementExtension\Logs" # This path is pulled when Intune collects diagnostics. `$logFile = "`$(`$logDir)\my_remediation.log" # Rename this log file. Start-Transcript `$logFile try { # Your script logic goes here } catch { Write-Error "An error occurred: `$_" } Stop-Transcript Exit "@ $remediationScript | Out-File -FilePath $path\scripts\$workSpaceName"_remediation.ps1" -Encoding UTF8 -Force Write-Output " Default remediation script created" #--------------------------------------------- Create Example File -------------------------------------------- $makeApp = @" `$makeExample = @" # detection.ps1 # Detect if Notepad++ is installed ```$AppName = "Notepad++" ```$Installed = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue | Where-Object { ```$_.DisplayName -like "*```$AppName*" } if (```$Installed) { Write-Output "```$AppName is installed." exit 0 # Detection: compliant } else { Write-Output "```$AppName is NOT installed." exit 1 # Detection: non-compliant } # remediation.ps1 # Install Notepad++ if not present ```$AppName = "Notepad++" ```$Installed = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue | Where-Object { ```$_.DisplayName -like "*```$AppName*" } if (-not ```$Installed) { ```$InstallerUrl = "https://github.com/notepad-plus-plus/notepad-plus-plus/releases/latest/download/npp.8.6.7.Installer.x64.exe" ```$InstallerPath = "```$env:TEMP\npp_installer.exe" Invoke-WebRequest -Uri ```$InstallerUrl -OutFile ```$InstallerPath Start-Process -FilePath ```$InstallerPath -ArgumentList "/S" -Wait Remove-Item ```$InstallerPath -Force } `"@ `$makeExample | Out-File -FilePath "$path\scripts\examples.ps1" -Encoding UTF8 -Force "@ $makeApp | Out-File -FilePath "$taskFolderPath\makeExample.ps1" -Encoding UTF8 -Force Write-Output " Generate example file task created" # --------------------------------------------------- Finish up ------------------------------------------------------------- Write-Output "Intune remediation scripts VS Code workspace creation completed" Write-Output `n $openWorkspace = Read-Host "Do you want to open the workspace in VS Code now? [Y or N]" if ($openWorkspace -eq "Y" -or $openWorkspace -eq "y") { try { #invoke-item $workspaceFilePath -ErrorAction SilentlyContinue code $workspaceFilePath #-NoNewWindow -ErrorAction SilentlyContinue Write-Output "Workspace opened in VS Code." Exit } catch { Write-Host "Unable to open VS Code. Please check if VS Code is installed." # Uncomment the line below to see the error details # Write-Output "Error: $_" } $portable = Read-Host "Do you want to use VSCode Portable to open the workspace? [Y or N]" if ($portable -eq "Y" -or $portable -eq "y") { try { #If VS Code portable is already installed, use it. $vsCodePortablePath = "$outDir\.VSCodePortable\Code.exe" if (Test-Path $vsCodePortablePath){ Start-Process -FilePath $vsCodePortablePath -ArgumentList """$workspaceFilePath""" Write-Output "Workspace opened in VS Code Portable." Exit } } catch { #VS Code portable is NOT installed $vsCodePortablePath = "$outDir\.VSCodePortable\Code.exe" $vscodePath = Join-Path $outDir ".VSCodePortable" if (-not (Test-Path -Path $vscodePath)) { New-Item -ItemType Directory -Path $vscodePath | Out-Null } # Find processor architecture for download link https://code.visualstudio.com/download $architecture = (Get-WMIObject -Class Win32_Processor).Architecture if ($architecture -eq 9) { #x64 $vscodeZip = "https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-archive" } elseif ($architecture -eq 5) { #arm64 $vscodeZip = "https://code.visualstudio.com/sha/download?build=stable&os=win32-arm64-archive" } else { Write-Host "Unsupported architecture: $architecture" -ForegroundColor Red } # Download VS Code portable .zip $vscodeFile = "VSCodePortable.zip" $vscodeOutFile = Join-Path $vscodePath $vscodeFile Write-Output " Downloading and extracting VS Code Portable..." Invoke-WebRequest -Uri $vscodeZip -OutFile $vscodeOutFile -UseBasicParsing if (-not (Test-Path -Path $vscodeOutFile)) { Write-Host "Failed to download VS Code Portable. Please check your internet connection." -ForegroundColor Red Write-Host "Direct download link is $vscodeZip" -ForegroundColor }else { # Extract the downloaded .zip file Expand-Archive -Path $vscodeOutFile -DestinationPath $vscodePath -Force # Delete .zip file after extraction Remove-Item -Path $vscodeOutFile -Force Write-Output "VS Code Portable downloaded to $vscodePath" # Open workspace? $openWorkspace = Read-Host "Do you want to open the workspace in VS Code now? [Y or N]" if ($openWorkspace -eq "Y" -or $openWorkspace -eq "y") { $vscode = Join-Path -Path $vscodePath -ChildPath "\Code.exe" start-process $vscode -ArgumentList """$workspaceFilePath""" -NoNewWindow -ErrorAction SilentlyContinue Write-Output "Workspace opened in VS Code." Write-Output "You can also open the workspace later by double-clicking the $Shortcut created in $outDir" Write-Output `n Start-Sleep -seconds 10 Exit } } } } } else { Write-Output "You chose not to open the workspace." `n Write-Output "You can open the workspace later by double-clicking the $workSpaceName workspace shortcut created in $outDir" `n Write-Output "Good-bye." `n } Exit |