├── AddSharedPrintersIntune.ps1 ├── AutoEnrollAlreadyAzureADJoined.ps1 ├── Create-AutoPilotDevicesDynamicGroup.ps1 ├── Create-IntuneUsersDynamicGroup.ps1 ├── CreateRegistryKeyForCurrentUserAsSystem.ps1 ├── DriveMap+Logonscript.ps1 ├── Install-WingetTools.intunewin ├── Install-WingetTools.ps1 ├── Install-WingetTools_Detection.ps1 ├── Invoke-ADCSCertMappingNDES.ps1 ├── PinToTaskbar.ps1 ├── Remove-LocalAdminPrivelageDETECTION.ps1 ├── Remove-LocalAdminPrivelageREMEDIATION.ps1 ├── RemoveDuplicatedShortcuts_plustask.ps1 ├── Volume_Shadow_Copy_Task.ps1 ├── Winget-InstallDetection.ps1 ├── Winget-InstallPackage.intunewin ├── Winget-InstallPackage.ps1 ├── Winget-InstallStorePackage-Detection.ps1 ├── Winget-InstallStorePackage.ps1 ├── Winget-UpgradeSelect.ps1 ├── WingetUpgrade-ProactiveDetection.ps1 ├── WingetUpgrade-Remediation.ps1 ├── WingetUpgradeTask.ps1 ├── chromebookmarks.ps1 ├── map-printers-scheduledtask.ps1 ├── powersettings.ps1 ├── remove-localadmins.ps1 ├── set_startmenu_taskbar_layout.ps1 ├── sharepoint_trustedsites.ps1 ├── startmenu_layout_plus_scheduledtask.ps1 └── teams_firewallrules.ps1 /AddSharedPrintersIntune.ps1: -------------------------------------------------------------------------------- 1 | # This first section adds the registry keys for point and print. This allows standard users to install printers. 2 | # Enter the trusted printers by FQDN below 3 | $printServers = @( 4 | "PrintServer1.domain.local" 5 | "PrintServer2.domain.local" 6 | ) 7 | #endregion 8 | #region PnP retrictions 9 | $hklmKeys = @( 10 | [PSCustomObject]@{ 11 | Name = "Restricted" 12 | Type = "DWORD" 13 | Value = "1" 14 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 15 | } 16 | [PSCustomObject]@{ 17 | Name = "TrustedServers" 18 | Type = "DWORD" 19 | Value = "1" 20 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 21 | } 22 | [PSCustomObject]@{ 23 | Name = "InForest" 24 | Type = "DWord" 25 | Value = "0" 26 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 27 | } 28 | [PSCustomObject]@{ 29 | Name = "NoWarningNoElevationOnInstall" 30 | Type = "DWord" 31 | Value = "1" 32 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 33 | } 34 | [PSCustomObject]@{ 35 | Name = "UpdatePromptSettings" 36 | Type = "DWord" 37 | Value = "2" 38 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 39 | } 40 | [PSCustomObject]@{ 41 | Name = "ServerList" 42 | Type = "String" 43 | Value = $printServers -join ";" 44 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 45 | } 46 | [PSCustomObject]@{ 47 | Name = "RestrictDriverInstallationToAdministrators" 48 | Type = "DWORD" 49 | Value = "0" 50 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" 51 | } 52 | ) 53 | $hklmKeys += [PSCustomObject]@{ 54 | Name = "PackagePointAndPrintServerList" 55 | Type = "DWORD" 56 | Value = "1" 57 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PackagePointAndPrint" 58 | } 59 | foreach ($p in $printServers) { 60 | $hklmKeys += [PSCustomObject]@{ 61 | Name = $p 62 | Type = "String" 63 | Value = $p 64 | Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PackagePointAndPrint\ListofServers" 65 | } 66 | } 67 | 68 | function Set-ComputerRegistryValues { 69 | param ( 70 | [Parameter(Mandatory = $true)] 71 | [array]$RegistryInstance 72 | ) 73 | try { 74 | foreach ($key in $RegistryInstance) { 75 | $keyPath = "$($key.Path)" 76 | if (!(Test-Path $keyPath)) { 77 | Write-Host "Registry path : $keyPath not found. Creating now." -ForegroundColor Green 78 | New-Item -Path $keyPath -Force | Out-Null 79 | Write-Host "Creating item property: $($key.Name)" -ForegroundColor Green 80 | New-ItemProperty -Path $keyPath -Name $key.Name -Value $key.Value -PropertyType $key.Type -Force 81 | } 82 | else { 83 | Write-Host "Creating item property: $($key.Name)" -ForegroundColor Green 84 | New-ItemProperty -Path $keyPath -Name $key.Name -Value $key.Value -PropertyType $key.Type -Force 85 | } 86 | } 87 | } 88 | catch { 89 | Throw $_.Exception.Message 90 | } 91 | } 92 | #endregion 93 | Set-ComputerRegistryValues -RegistryInstance $hklmKeys 94 | 95 | ###################################################################################################################################################### 96 | # This next section creates a scheduled task to run as the logged on user. This will auto map the printers if they are not already mapped at user login 97 | # Also added a trigger when a user connects to VPN using the built in Windows VPN client. 98 | ####################################################################################################################################################### 99 | 100 | $script= @' 101 | if ((Get-Printer | where name -like "\\PrintServer1.domain.local\Printer1")) 102 | { 103 | exit 104 | } 105 | $fp01= Test-Connection -ComputerName PrintServer1.domain.local -Quiet 106 | if ($fp01) { 107 | add-printer -ConnectionName "\\PrintServer1.domain.local\Printer1" 108 | add-printer -ConnectionName "\\PrintServer1.domain.local\Printer2" 109 | } 110 | ELSE 111 | { 112 | exit 113 | } 114 | '@ 115 | 116 | # Create a directory for our login script 117 | if ( -not (Test-Path -Path c:\automation) ) 118 | { 119 | new-item c:\automation -ItemType directory -force 120 | } 121 | set-content c:\automation\addprinters.ps1 $script 122 | 123 | if( -Not (Get-ScheduledTask -TaskName "Add Shared Printers" -ErrorAction SilentlyContinue -OutVariable task) ) 124 | { 125 | $Params = @{ 126 | Action = (New-ScheduledTaskAction -Execute 'powershell' -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass c:\automation\addprinters.ps1') 127 | Trigger = (New-ScheduledTaskTrigger -AtLogOn) 128 | Principal = (New-ScheduledTaskPrincipal -UserId (Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -expand UserName)) 129 | TaskName = 'Add Shared Printers' 130 | Description = 'Add Shared Printers' 131 | } 132 | Register-ScheduledTask @Params 133 | 134 | # Add trigger for connection to VPN 135 | $CIMTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger 136 | $Trigger = @( 137 | (New-CimInstance -CimClass $CIMTriggerClass -ClientOnly), 138 | (New-ScheduledTaskTrigger -AtLogOn) 139 | ) 140 | $Trigger[0].Subscription = 141 | @" 142 | 143 | "@ 144 | $Trigger[0].Enabled = $True 145 | 146 | Set-Scheduledtask "Add Shared Printers" -Trigger $Trigger 147 | 148 | Start-ScheduledTask -TaskName "Add Shared Printers" 149 | } 150 | else 151 | { 152 | $CIMTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger -Namespace Root/Microsoft/Windows/TaskScheduler:MSFT_TaskEventTrigger 153 | $Trigger = @( 154 | (New-CimInstance -CimClass $CIMTriggerClass -ClientOnly), 155 | (New-ScheduledTaskTrigger -AtLogOn) 156 | ) 157 | $Trigger[0].Subscription = 158 | @" 159 | 160 | "@ 161 | $Trigger[0].Enabled = $True 162 | 163 | Set-Scheduledtask "Add Shared Printers" -Trigger $Trigger 164 | 165 | Start-ScheduledTask -TaskName "Add Shared Printers" 166 | } 167 | 168 | -------------------------------------------------------------------------------- /AutoEnrollAlreadyAzureADJoined.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Create a scheduled task and apply registry keys to force auto enrollment to MDM for already 3 | AzureAD joined devices. These are the same actions applied when applying the Auto enroll MDM GPO settings. 4 | #> 5 | $RegKey ="HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\" 6 | 7 | $RegKey1 ="HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\MDM" 8 | 9 | $ScheduleName ="Schedule created by enrollment client for automatically enrolling in MDM from AAD" 10 | 11 | $Date = Get-Date -Format "yyyy-MM-dd" 12 | 13 | $Time = (Get-date).AddMinutes(5).ToString("HH:mm:ss") 14 | 15 | 16 | 17 | $ST = @" 18 | 19 | 20 | 21 | Microsoft Corporation 22 | \Microsoft\Windows\EnterpriseMgmt\Schedule created by enrollment client for automatically enrolling in MDM from AAD 23 | D:P(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;LS) 24 | 25 | 26 | 27 | 28 | PT5M 29 | P1D 30 | true 31 | 32 | $($Date)T$($Time) 33 | true 34 | 35 | 36 | 37 | 38 | S-1-5-18 39 | LeastPrivilege 40 | 41 | 42 | 43 | Queue 44 | false 45 | false 46 | true 47 | true 48 | true 49 | 50 | false 51 | false 52 | 53 | true 54 | true 55 | false 56 | false 57 | false 58 | true 59 | false 60 | PT1H 61 | 7 62 | 63 | 64 | 65 | %windir%\system32\deviceenroller.exe 66 | /c /AutoEnrollMDM 67 | 68 | 69 | 70 | 71 | "@ 72 | 73 | 74 | 75 | 76 | 77 | New-Item -Path $RegKey -Name MDM 78 | 79 | New-ItemProperty -Path $RegKey1 -Name AutoEnrollMDM -Value 1 80 | 81 | New-ItemProperty -Path $RegKey1 -Name UseAADCredentialType -Value 1 82 | 83 | (Register-ScheduledTask -XML $ST -TaskName $ScheduleName -Force) | Out-null -------------------------------------------------------------------------------- /Create-AutoPilotDevicesDynamicGroup.ps1: -------------------------------------------------------------------------------- 1 | Install-Module azureadpreview -AllowClobber -Force -Confirm:$false 2 | Import-Module AzureADPreview 3 | Connect-AzureAD 4 | 5 | #Create Dynamic Device Group for Autopilot 6 | 7 | $AutoPilotGroup = @{ 8 | DisplayName = "Autopilot Devices" 9 | Description ="Dynamic Group for Autpilot Devices" 10 | GroupTypes = "DynamicMembership" 11 | Membershiprule = '(device.devicePhysicalIDs -any _ -contains "[ZTDId]")' 12 | MailEnabled = $False 13 | MailNickName = 'AutopilotDevices' 14 | SecurityEnabled = $True 15 | MembershipRuleProcessingState = "On" 16 | } 17 | if ((Get-AzureADMSGroup | Where Displayname -like "Autopilot Devices") -eq $Null){ 18 | 19 | New-AzureADMSGroup @AutopilotGroup 20 | } 21 | Disconnect-AzureAD -------------------------------------------------------------------------------- /Create-IntuneUsersDynamicGroup.ps1: -------------------------------------------------------------------------------- 1 | Connect-MGGraph -Scope "Directory.ReadWrite.All" 2 | $GroupParams = @{ 3 | DisplayName = "Intune Users" 4 | Description ="Dynamic Group for Intune Users" 5 | GroupTypes = "DynamicMembership" 6 | Membershiprule = '(user.assignedPlans -any (assignedPlan.servicePlanId -eq "c1ec4a95-1f05-45b3-a911-aa3fa01094f5" -and assignedPlan.capabilityStatus -eq "Enabled"))' 7 | MailEnabled = $False 8 | MailNickName = 'AutopilotDevices' 9 | SecurityEnabled = $True 10 | MembershipRuleProcessingState = "On" 11 | } 12 | New-MGGroup -BodyParameter $GroupParams 13 | Disconnect-MGGraph -------------------------------------------------------------------------------- /CreateRegistryKeyForCurrentUserAsSystem.ps1: -------------------------------------------------------------------------------- 1 | #This script will load the HKU registry path for the current user and allow you to modify their hive as system/administrator 2 | #This is sometimes needed as user may not have permission to create keys/write values to their HKCU hive 3 | 4 | $UserSID = (New-Object -ComObject Microsoft.DiskQuota).TranslateLogonNameToSID((Get-WmiObject -Class Win32_ComputerSystem).Username) 5 | 6 | $Path = "HKU\$UserSID\PATH_TO_KEY_TO_CREATE" 7 | New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS 8 | Reg Add $path /f 9 | reg add $path /v DWORDNAME /t REG_DWORD /d 1 /f 10 | -------------------------------------------------------------------------------- /DriveMap+Logonscript.ps1: -------------------------------------------------------------------------------- 1 | $ServerName = #Enter the FQDN of the file server 2 | $DriveLetter = #Enter drive letter 3 | $TaskName = $DriveLetter + " Drive Map" 4 | $UNCPath = #Enter UNC file path for fileshare 5 | 6 | $tasks = get-scheduledtask -taskpath '\' | select -ExpandProperty taskname 7 | if ($tasks -like $TaskName){Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false ; write-host "Task Unregistered" } 8 | $gmapscript= @" 9 | sleep 20 10 | `$fp01 = Test-Connection -ComputerName $ServerName -ErrorAction SilentlyContinue 11 | `$UNCPath = $UNCPath 12 | if (`$fp01) { 13 | net use $($DriveLetter): /delete 14 | net use $($DriveLetter): `$UNCPath 15 | } 16 | "@ 17 | if ( -not (Test-Path -Path c:\automation) ) 18 | { 19 | new-item c:\automation -ItemType directory -force 20 | } 21 | set-content c:\automation\$($DriveLetter + 'drivemap.ps1') $gmapscript 22 | 23 | $action = New-ScheduledTaskAction -Execute 'powershell' -Argument "-ExecutionPolicy Bypass -NoProfile -WindowStyle Minimized -File $($DriveLetter + 'drivemap.ps1')" 24 | $trigger = New-ScheduledTaskTrigger -AtLogOn 25 | $principal = New-ScheduledTaskPrincipal -UserId (Get-CimInstance –ClassName Win32_ComputerSystem | Select-Object -expand UserName) 26 | $task = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal 27 | Register-ScheduledTask $TaskName -InputObject $task 28 | Start-ScheduledTask -TaskName $TaskName 29 | -------------------------------------------------------------------------------- /Install-WingetTools.intunewin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djust270/Intune-Scripts/62f388a7c8116c4f8c975bcd27d6e883c60e75c5/Install-WingetTools.intunewin -------------------------------------------------------------------------------- /Install-WingetTools.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 8/22/2022 9:30 AM 6 | Created by: David Just 7 | Filename: Install-WingetTools 8 | =========================================================================== 9 | .DESCRIPTION 10 | This script will Install Winget and the WingetTools PowerShell module. 11 | #> 12 | 13 | #region functions 14 | function Install-VisualC #Install VisualC++ 2015-2022 x64 15 | { 16 | $url = 'https://aka.ms/vs/17/release/vc_redist.x64.exe' 17 | $WebClient = New-Object System.Net.WebClient 18 | $WebClient.DownloadFile('https://aka.ms/vs/17/release/vc_redist.x64.exe', "$env:Temp\vc_redist.x64.exe") 19 | $WebClient.Dispose() 20 | start-process "$env:temp\vc_redist.x64.exe" -argumentlist "/q /norestart" -Wait 21 | } 22 | 23 | function Get-RegUninstallKey #Enumerate registry uninstall keys 24 | { 25 | param ( 26 | [string]$DisplayName 27 | ) 28 | $ErrorActionPreference = 'Continue' 29 | $uninstallKeys = "registry::HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall", "registry::HKLM\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall", "registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall" 30 | $softwareTable = @() 31 | 32 | foreach ($key in $uninstallKeys) 33 | { 34 | $softwareTable += Get-Childitem $key | Get-ItemProperty | where displayname | Sort-Object -Property displayname 35 | } 36 | if ($DisplayName) 37 | { 38 | $softwareTable | where displayname -Like "*$DisplayName*" 39 | } 40 | else 41 | { 42 | $softwareTable | Sort-Object -Property displayname -Unique 43 | } 44 | 45 | } 46 | 47 | function Install-WingetTools #Install the WingetTools module. 48 | { 49 | Install-PackageProvider -Name NuGet -Force 50 | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 51 | Install-Module -Name WingetTools 52 | if (-Not [bool](Get-Module -ListAvailable -Name WingetTools)) 53 | { 54 | $GithubURL = "https://github.com/jdhitsolutions/WingetTools/archive/refs/heads/main.zip" 55 | $ModuleZipFile = "$Env:TEMP\WingetTools.zip" 56 | $WebClient = [System.Net.WebClient]::new() 57 | $WebClient.DownloadFile($GithubURL, $ModuleZipFile) 58 | Expand-Archive -Path "$Env:TEMP\WingetTools.zip" -DestinationPath "$env:windir\System32\WindowsPowerShell\v1.0\Modules" 59 | Rename-Item -Path "$env:windir\System32\WindowsPowerShell\v1.0\Modules\WingetTools-main" -NewName "WingetTools" 60 | } 61 | } 62 | 63 | function Install-WingetAsSystem # Install WinGet as logged on user by creating a scheduled task 64 | { 65 | $script = @' 66 | # Adapted from https://github.com/microsoft/winget-pkgs/blob/master/Tools/SandboxTest.ps1 (better than my original code!) 67 | # This will install the latest version of WinGet and its dependancies 68 | $tempFolderName = 'WinGetInstall' 69 | $tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $tempFolderName 70 | New-Item $tempFolder -ItemType Directory -ErrorAction SilentlyContinue | Out-Null 71 | 72 | $apiLatestUrl = 'https://api.github.com/repos/microsoft/winget-cli/releases/latest' 73 | 74 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 75 | $WebClient = New-Object System.Net.WebClient 76 | 77 | function Get-LatestUrl { 78 | ((Invoke-WebRequest $apiLatestUrl -UseBasicParsing | ConvertFrom-Json).assets | Where-Object { $_.name -match '^Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle$' }).browser_download_url 79 | } 80 | 81 | function Get-LatestHash { 82 | $shaUrl = ((Invoke-WebRequest $apiLatestUrl -UseBasicParsing | ConvertFrom-Json).assets | Where-Object { $_.name -match '^Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.txt$' }).browser_download_url 83 | 84 | $shaFile = Join-Path -Path $tempFolder -ChildPath 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.txt' 85 | $WebClient.DownloadFile($shaUrl, $shaFile) 86 | 87 | Get-Content $shaFile 88 | } 89 | 90 | $desktopAppInstaller = @{ 91 | fileName = 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle' 92 | url = $(Get-LatestUrl) 93 | hash = $(Get-LatestHash) 94 | } 95 | 96 | $vcLibsUwp = @{ 97 | fileName = 'Microsoft.VCLibs.x64.14.00.Desktop.appx' 98 | url = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx' 99 | hash = '9BFDE6CFCC530EF073AB4BC9C4817575F63BE1251DD75AAA58CB89299697A569' 100 | } 101 | $uiLibsUwp = @{ 102 | fileName = 'Microsoft.UI.Xaml.2.7.zip' 103 | url = 'https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.0' 104 | hash = '422FD24B231E87A842C4DAEABC6A335112E0D35B86FAC91F5CE7CF327E36A591' 105 | } 106 | 107 | $dependencies = @($desktopAppInstaller, $vcLibsUwp, $uiLibsUwp) 108 | 109 | Write-Host '--> Checking dependencies' 110 | 111 | foreach ($dependency in $dependencies) { 112 | $dependency.file = Join-Path -Path $tempFolder -ChildPath $dependency.fileName 113 | #$dependency.pathInSandbox = (Join-Path -Path $tempFolderName -ChildPath $dependency.fileName) 114 | 115 | # Only download if the file does not exist, or its hash does not match. 116 | if (-Not ((Test-Path -Path $dependency.file -PathType Leaf) -And $dependency.hash -eq $(Get-FileHash $dependency.file).Hash)) { 117 | Write-Host @" 118 | - Downloading: 119 | $($dependency.url) 120 | "@ 121 | 122 | try { 123 | $WebClient.DownloadFile($dependency.url, $dependency.file) 124 | } catch { 125 | #Pass the exception as an inner exception 126 | throw [System.Net.WebException]::new("Error downloading $($dependency.url).", $_.Exception) 127 | } 128 | if (-not ($dependency.hash -eq $(Get-FileHash $dependency.file).Hash)) { 129 | throw [System.Activities.VersionMismatchException]::new('Dependency hash does not match the downloaded file') 130 | } 131 | } 132 | } 133 | 134 | # Extract Microsoft.UI.Xaml from zip (if freshly downloaded). 135 | # This is a workaround until https://github.com/microsoft/winget-cli/issues/1861 is resolved. 136 | 137 | if (-Not (Test-Path (Join-Path -Path $tempFolder -ChildPath \Microsoft.UI.Xaml.2.7\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx))) { 138 | Expand-Archive -Path $uiLibsUwp.file -DestinationPath ($tempFolder + '\Microsoft.UI.Xaml.2.7') -Force 139 | } 140 | $uiLibsUwp.file = (Join-Path -Path $tempFolder -ChildPath \Microsoft.UI.Xaml.2.7\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx) 141 | Add-AppxPackage -Path $($desktopAppInstaller.file) -DependencyPath $($vcLibsUwp.file),$($uiLibsUwp.file) 142 | # Clean up files 143 | Remove-Item $tempFolder -recurse -force 144 | '@ 145 | if (!(test-path "$env:systemdrive\automation")) { mkdir "$env:systemdrive\automation" } 146 | $script | out-file "$env:systemdrive\automation\script.ps1" 147 | $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-executionpolicy bypass -WindowStyle minimized -file %HOMEDRIVE%\automation\script.ps1" 148 | $trigger = New-ScheduledTaskTrigger -AtLogOn 149 | $principal = New-ScheduledTaskPrincipal -UserId (Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -expand UserName) 150 | $task = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal 151 | Register-ScheduledTask RunScript -InputObject $task 152 | Start-ScheduledTask -TaskName RunScript 153 | Start-Sleep -Seconds 120 154 | Unregister-ScheduledTask -TaskName RunScript -Confirm:$false 155 | Remove-Item C:\automation\script.ps1 156 | } 157 | 158 | 159 | function Write-Log($message) #Log script messages to temp directory 160 | { 161 | $LogMessage = ((Get-Date -Format "MM-dd-yy HH:MM:ss ") + $message) 162 | Out-File -InputObject $LogMessage -FilePath "$LogPath\$LogFullName" -Append -Encoding utf8 163 | } 164 | 165 | #endregion 166 | #region pre-requsites 167 | $LogName = 'WinGetToolsInstall' 168 | $LogDate = Get-Date -Format dd-MM-yy_HH-mm # go with the EU format day / month / year 169 | $LogFullName = "$LogName-$LogDate.log" 170 | $LogPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs" 171 | 172 | $InstalledModules = Get-Module -ListAvailable 173 | $WinGetToolsInstalled = [bool]($InstalledModules | Where-Object name -EQ "WingetTools") 174 | $ThreadJobInstalled = [bool]($InstalledModules | Where-Object name -EQ "ThreadJob") 175 | 176 | if (-Not $WinGetToolsInstalled) { Install-WingetTools } # Install WingetTools if not available 177 | 178 | if (-Not $ThreadJobInstalled) # Install ThreadJob module if not installed 179 | { 180 | Install-PackageProvider Nuget -Force 181 | Set-PackageSource -Name PSGallery -Trusted 182 | Install-Module -Name threadjob 183 | } 184 | 185 | Set-ExecutionPolicy bypass -Scope Process -Force 186 | Import-Module WingetTools 187 | $WingetPath = Get-WGPath 188 | $VisualC = Get-RegUninstallKey -DisplayName "Microsoft Visual C++ 2015-2022 Redistributable (x64)" 189 | $loggedOnUser = (Get-CimInstance win32_computersystem).username 190 | 191 | # If Visual C++ Redist. not installed, install it 192 | if (!$VisualC) 193 | { 194 | Write-Log -message "Visual C++ X64 not found. Attempting to install" 195 | try 196 | { 197 | Install-VisualC 198 | } 199 | Catch [System.InvalidOperationException]{ 200 | Write-Log -message "Error installing visual c++ redistributable. Attempting install once more" 201 | Start-Sleep -Seconds 5 202 | Install-VisualC 203 | } 204 | Catch 205 | { 206 | Write-Log -message "Failed to install visual c++ redistributable!" 207 | Write-Log -message $_ 208 | exit 1 209 | } 210 | $VisualC = Get-RegUninstallKey -DisplayName "Microsoft Visual C++ 2015-2022 Redistributable (x64)" 211 | if (-Not $VisualC) { Write-Log -message "Visual C++ Redistributable not found!"; exit 1 } 212 | else { Write-Log -message "Successfully installed Microsoft Visual C++ 2015-2022 Redistributable (x64)" } 213 | } 214 | 215 | if (-Not $WingetPath) 216 | { 217 | if ($loggedOnUser) 218 | { 219 | Write-Log -message "Attempting to install Winget as System under $($loggedOnUser)" 220 | Install-WingetAsSystem 221 | # If more than one version of Winget, select the latest 222 | $WingetPath = Get-WGPath 223 | if ($WingetPath.count -gt 1) { $WingetPath = $Winget[-1] } 224 | if (-Not $WingetPath) { "Winget not found after attempting install as system. Exiting."; exit 1 } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Install-WingetTools_Detection.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 8/22/2022 10:14 AM 6 | Created by: David Just 7 | Organization: 8 | Filename: 9 | =========================================================================== 10 | .DESCRIPTION 11 | Detection script for Install-WingetTools 12 | #> 13 | 14 | $WingetTools = [bool](Get-Module -ListAvailable -Name WingetTools) 15 | if ($WingetTools) 16 | { 17 | "WingetTools is installed" 18 | exit 0 19 | } 20 | else 21 | { 22 | "WingetTools is not installed!" 23 | exit 1 24 | } 25 | -------------------------------------------------------------------------------- /Invoke-ADCSCertMappingNDES.ps1: -------------------------------------------------------------------------------- 1 | #requires -module PSPKI 2 | # Sourced from https://system32.blog/post/adsmapcertificates/ 3 | #region Static Definitions 4 | [string]$CertAuthority = "CA" 5 | [array]$CertTemplates = 'Template Name' 6 | [bool]$DryRun = $true 7 | [string]$NDESServiceAccount = '' 8 | [string]$Domain = '' 9 | #endregion 10 | 11 | #region Modules 12 | Import-Module -Name 'PSPKI' 13 | #endregion 14 | 15 | #region Functions 16 | 17 | # Thanks to Reddit / Github User xxdcmast for this function @xxdcmast, if you want me to remove this, let me know 18 | function Reverse-CertificateIssuer { 19 | [CmdletBinding()] 20 | Param( 21 | [Parameter(Position = 0, mandatory = $true)] 22 | [string] $CertIssuer) 23 | 24 | #Split the issuer DN into parts by comma 25 | $CertIssuernospaces = $CertIssuer -replace ',\s',',' 26 | $splitresults =$CertIssuernospaces -split "," -ne '' 27 | 28 | #Reverse the DN to create the reverse issuer 29 | $reversed =$splitresults[-1.. - $splitresults.Length] -join ', ' 30 | 31 | $reversed.trimstart() 32 | 33 | #end function 34 | } 35 | # Thanks to Reddit / Github User xxdcmast for this function @xxdcmast, if you want me to remove this, let me know 36 | function Reverse-CertificateSerialNumber { 37 | [CmdletBinding()] 38 | Param( 39 | [Parameter(Position=0,mandatory=$true)] 40 | [string] $CertSerialNumber) 41 | 42 | #Split the string into two characters to represent the byte encoding 43 | $splitresults = $CertSerialNumber -split '(..)' -ne '' 44 | 45 | #Take the byte split serial number and reverse the digits to get the correct cert formatting 46 | $splitresults[-1..-$splitresults.Length] -join '' 47 | 48 | #end function 49 | } 50 | #endregion 51 | 52 | #region Retrieve Data 53 | $CAs = @{} 54 | 55 | # Retrieve all Certificate Templates and their OIDs 56 | Write-Host("[$(Get-Date)] Retrieving Certificate templates..") 57 | $CertTemplateOIDs = $CertTemplates | ForEach-Object { 58 | (Get-CertificateTemplate -Name $_).oid.Value 59 | } 60 | 61 | # Retrieve all trusted domains 62 | Write-Host("[$(Get-Date)] Retrieving all trusted domains..") 63 | $Domains = @{} 64 | 65 | Get-ADTrust -Filter * | ForEach-Object { 66 | [string]$DC = (Get-ADDomainController -Discover -DomainName $_.target).hostname 67 | $ADDomain = Get-ADDomain -Server $DC 68 | $NETBIOS = $ADDomain.NetBIOSName 69 | $Domains.$NETBIOS = @{ 70 | DomainController = $DC 71 | } 72 | } 73 | [string]$DC = (Get-ADDomainController -Discover).hostname 74 | $ADDomain = Get-ADDomain -Server $DC 75 | $NETBIOS = $ADDomain.NetBIOSName 76 | $Domains.$NETBIOS = @{ 77 | DomainController = $DC 78 | IsLocal = $true 79 | } 80 | # Retrieve all certificates that match our template 81 | Write-Host("[$(Get-Date)] Retrieving Certificates..") 82 | $certs = Get-IssuedRequest -CertificationAuthority $CertAuthority -Filter "NotAfter -ge $(Get-Date)" | Where-Object { 83 | $_.CertificateTemplate -in $CertTemplateOIDs 84 | } 85 | #endregion 86 | 87 | #region Map certificates 88 | Write-Host("[$(Get-Date)] Processing Certificates..") 89 | foreach($cert in ($certs | where request.requestername -eq $NDESServiceAccount | sort requestid)){ 90 | $requester = $cert.'CommonName' 91 | $CN = $requester 92 | 93 | # Check if we found this domain 94 | if( 95 | ($DomainEntry = $Domains.GetEnumerator() | Where-Object { $_.Name -eq $Domain }) 96 | ){ 97 | # Build AD Cmdlet Splatting 98 | $ADCmdletSplat = @{ 99 | Server = $DomainEntry.Value.DomainController 100 | } 101 | 102 | # Check if this is the local domain, otherwise ask for credentials 103 | if( 104 | !($DomainEntry.Value.IsLocal) -and 105 | !($DomainEntry.Value.Credentials) 106 | ){ 107 | $Domains.$Domain.Credentials = Get-Credential -Message "Please enter Credentials for Domain `"$Domain`"." 108 | $DomainEntry.Value.Credentials = $Domains.$Domain.Credentials 109 | } 110 | 111 | # Add the credential to the splatting if we have one 112 | if(!($DomainEntry.Value.IsLocal)){ 113 | $ADCmdletSplat.Credential = $DomainEntry.Value.Credentials 114 | } 115 | 116 | # Retrieve AD Object 117 | if($ADObject = Get-ADObject -Filter { UserPrincipalName -eq $CN } -Properties 'altSecurityIdentities' -ErrorAction SilentlyContinue @ADCmdletSplat){ 118 | if(!($CAs.$($cert.ConfigString))){ 119 | $CAs.$($cert.ConfigString) = Get-CA -ErrorAction SilentlyContinue | Where-Object { $_.ConfigString -eq $cert.ConfigString } 120 | } 121 | 122 | # Build CA Cert Subject 123 | $CACertSubject = (Reverse-CertificateIssuer -CertIssuer $CAs.$($cert.ConfigString).Certificate.Subject).Replace(" ","") 124 | 125 | # Build Serial Numbers 126 | $CertForwardSN = $cert.SerialNumber 127 | $CertBackwardSN = (Reverse-CertificateSerialNumber -CertSerialNumber $CertForwardSN).ToUpper() 128 | 129 | # Build X509 Address 130 | $X509IssuerSerialNumber = "X509:$CACertSubject$CertBackwardSN" 131 | 132 | # Check if the attribute is already set, otherwise initialize array 133 | if(!($altIDs = $ADObject.'altSecurityIdentities')){ 134 | $altIDs = @() 135 | } 136 | 137 | # Check if our X509IssuerSerialNumber is already in it 138 | if($X509IssuerSerialNumber -notin $altIDs){ 139 | 140 | # It is not, add it 141 | Write-Host("[$($cert.RequestID) - $CN] Adding X509: `"$X509IssuerSerialNumber`"") 142 | $altIDs += $X509IssuerSerialNumber 143 | 144 | if(!$DryRun){ 145 | # Write out the AD Object 146 | $ADObject | Set-ADObject -Replace @{ 147 | 'altSecurityIdentities' = $altIDs 148 | } @ADCmdletSplat 149 | } 150 | } 151 | }else{ 152 | Write-Host("[$($cert.RequestID) - $CN] AD Object not found.") 153 | } 154 | } 155 | } 156 | #endregion 157 | 158 | -------------------------------------------------------------------------------- /PinToTaskbar.ps1: -------------------------------------------------------------------------------- 1 | # Pin to taskbar adapted from Pinto10 script https://pinto10blog.wordpress.com/2016/09/10/pinto10/ 2 | function Pin-ToTaskbar { 3 | [CmdletBinding()] 4 | param ( 5 | [string]$targetfile, 6 | [validateset('PIN','UNPIN')] 7 | [String]$Action 8 | ) 9 | 10 | 11 | function Masquerade-PEB { 12 | <# 13 | .SYNOPSIS 14 | Masquerade-PEB uses NtQueryInformationProcess to get a handle to powershell's 15 | PEB. From there itreplaces a number of UNICODE_STRING structs in memory to 16 | give powershell the appearance of a different process. Specifically, the 17 | function will overwrite powershell's "ImagePathName" & "CommandLine" in 18 | _RTL_USER_PROCESS_PARAMETERS and the "FullDllName" & "BaseDllName" in the 19 | _LDR_DATA_TABLE_ENTRY linked list. 20 | 21 | This can be useful as it would fool any Windows work-flows which rely solely 22 | on the Process Status API to check process identity. A practical example would 23 | be the IFileOperation COM Object which can perform an elevated file copy if it 24 | thinks powershell is really explorer.exe ;)! 25 | 26 | Notes: 27 | * Works on x32/64. 28 | 29 | * Most of these API's and structs are undocumented. I strongly recommend 30 | @rwfpl's terminus project as a reference guide! 31 | + http://terminus.rewolf.pl/terminus/ 32 | 33 | * Masquerade-PEB is basically a reimplementation of two functions in UACME 34 | by @hFireF0X. My code is quite different because, unfortunately, I don't 35 | have access to all those c++ goodies and I could not get a callback for 36 | LdrEnumerateLoadedModules working! 37 | + supMasqueradeProcess: https://github.com/hfiref0x/UACME/blob/master/Source/Akagi/sup.c#L504 38 | + supxLdrEnumModulesCallback: https://github.com/hfiref0x/UACME/blob/master/Source/Akagi/sup.c#L477 39 | 40 | .DESCRIPTION 41 | Author: Ruben Boonen (@FuzzySec) 42 | License: BSD 3-Clause 43 | Required Dependencies: None 44 | Optional Dependencies: None 45 | 46 | .EXAMPLE 47 | C:\PS> Masquerade-PEB -BinPath "C:\Windows\explorer.exe" 48 | #> 49 | 50 | param ( 51 | [Parameter(Mandatory = $True)] 52 | [string]$BinPath 53 | ) 54 | 55 | Add-Type -TypeDefinition @" 56 | using System; 57 | using System.Diagnostics; 58 | using System.Runtime.InteropServices; 59 | using System.Security.Principal; 60 | 61 | [StructLayout(LayoutKind.Sequential)] 62 | public struct UNICODE_STRING 63 | { 64 | public UInt16 Length; 65 | public UInt16 MaximumLength; 66 | public IntPtr Buffer; 67 | } 68 | 69 | [StructLayout(LayoutKind.Sequential)] 70 | public struct _LIST_ENTRY 71 | { 72 | public IntPtr Flink; 73 | public IntPtr Blink; 74 | } 75 | 76 | [StructLayout(LayoutKind.Sequential)] 77 | public struct _PROCESS_BASIC_INFORMATION 78 | { 79 | public IntPtr ExitStatus; 80 | public IntPtr PebBaseAddress; 81 | public IntPtr AffinityMask; 82 | public IntPtr BasePriority; 83 | public UIntPtr UniqueProcessId; 84 | public IntPtr InheritedFromUniqueProcessId; 85 | } 86 | 87 | /// Partial _PEB 88 | [StructLayout(LayoutKind.Explicit, Size = 64)] 89 | public struct _PEB 90 | { 91 | [FieldOffset(12)] 92 | public IntPtr Ldr32; 93 | [FieldOffset(16)] 94 | public IntPtr ProcessParameters32; 95 | [FieldOffset(24)] 96 | public IntPtr Ldr64; 97 | [FieldOffset(28)] 98 | public IntPtr FastPebLock32; 99 | [FieldOffset(32)] 100 | public IntPtr ProcessParameters64; 101 | [FieldOffset(56)] 102 | public IntPtr FastPebLock64; 103 | } 104 | 105 | /// Partial _PEB_LDR_DATA 106 | [StructLayout(LayoutKind.Sequential)] 107 | public struct _PEB_LDR_DATA 108 | { 109 | public UInt32 Length; 110 | public Byte Initialized; 111 | public IntPtr SsHandle; 112 | public _LIST_ENTRY InLoadOrderModuleList; 113 | public _LIST_ENTRY InMemoryOrderModuleList; 114 | public _LIST_ENTRY InInitializationOrderModuleList; 115 | public IntPtr EntryInProgress; 116 | } 117 | 118 | /// Partial _LDR_DATA_TABLE_ENTRY 119 | [StructLayout(LayoutKind.Sequential)] 120 | public struct _LDR_DATA_TABLE_ENTRY 121 | { 122 | public _LIST_ENTRY InLoadOrderLinks; 123 | public _LIST_ENTRY InMemoryOrderLinks; 124 | public _LIST_ENTRY InInitializationOrderLinks; 125 | public IntPtr DllBase; 126 | public IntPtr EntryPoint; 127 | public UInt32 SizeOfImage; 128 | public UNICODE_STRING FullDllName; 129 | public UNICODE_STRING BaseDllName; 130 | } 131 | 132 | public static class Kernel32 133 | { 134 | [DllImport("kernel32.dll")] 135 | public static extern UInt32 GetLastError(); 136 | 137 | [DllImport("kernel32.dll")] 138 | public static extern Boolean VirtualProtectEx( 139 | IntPtr hProcess, 140 | IntPtr lpAddress, 141 | UInt32 dwSize, 142 | UInt32 flNewProtect, 143 | ref UInt32 lpflOldProtect); 144 | 145 | [DllImport("kernel32.dll")] 146 | public static extern Boolean WriteProcessMemory( 147 | IntPtr hProcess, 148 | IntPtr lpBaseAddress, 149 | IntPtr lpBuffer, 150 | UInt32 nSize, 151 | ref UInt32 lpNumberOfBytesWritten); 152 | } 153 | 154 | public static class Ntdll 155 | { 156 | [DllImport("ntdll.dll")] 157 | public static extern int NtQueryInformationProcess( 158 | IntPtr processHandle, 159 | int processInformationClass, 160 | ref _PROCESS_BASIC_INFORMATION processInformation, 161 | int processInformationLength, 162 | ref int returnLength); 163 | 164 | [DllImport("ntdll.dll")] 165 | public static extern void RtlEnterCriticalSection( 166 | IntPtr lpCriticalSection); 167 | 168 | [DllImport("ntdll.dll")] 169 | public static extern void RtlLeaveCriticalSection( 170 | IntPtr lpCriticalSection); 171 | } 172 | "@ 173 | 174 | # Flag architecture $x32Architecture/!$x32Architecture 175 | if ([System.IntPtr]::Size -eq 4) { 176 | $x32Architecture = 1 177 | } 178 | 179 | # Current Proc handle 180 | $ProcHandle = (Get-Process -Id ([System.Diagnostics.Process]::GetCurrentProcess().Id)).Handle 181 | 182 | # Helper function to overwrite UNICODE_STRING structs in memory 183 | function Emit-UNICODE_STRING { 184 | param( 185 | [IntPtr]$hProcess, 186 | [IntPtr]$lpBaseAddress, 187 | [UInt32]$dwSize, 188 | [String]$data 189 | ) 190 | 191 | # Set access protections -> PAGE_EXECUTE_READWRITE 192 | [UInt32]$lpflOldProtect = 0 193 | $CallResult = [Kernel32]::VirtualProtectEx($hProcess, $lpBaseAddress, $dwSize, 0x40, [ref]$lpflOldProtect) 194 | 195 | # Create replacement struct 196 | $UnicodeObject = New-Object UNICODE_STRING 197 | $UnicodeObject_Buffer = $data 198 | [UInt16]$UnicodeObject.Length = $UnicodeObject_Buffer.Length*2 199 | [UInt16]$UnicodeObject.MaximumLength = $UnicodeObject.Length+1 200 | [IntPtr]$UnicodeObject.Buffer = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($UnicodeObject_Buffer) 201 | [IntPtr]$InMemoryStruct = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($dwSize) 202 | [system.runtime.interopservices.marshal]::StructureToPtr($UnicodeObject, $InMemoryStruct, $true) 203 | 204 | # Overwrite PEB UNICODE_STRING struct 205 | [UInt32]$lpNumberOfBytesWritten = 0 206 | $CallResult = [Kernel32]::WriteProcessMemory($hProcess, $lpBaseAddress, $InMemoryStruct, $dwSize, [ref]$lpNumberOfBytesWritten) 207 | 208 | # Free $InMemoryStruct 209 | [System.Runtime.InteropServices.Marshal]::FreeHGlobal($InMemoryStruct) 210 | } 211 | 212 | # Process Basic Information 213 | $PROCESS_BASIC_INFORMATION = New-Object _PROCESS_BASIC_INFORMATION 214 | $PROCESS_BASIC_INFORMATION_Size = [System.Runtime.InteropServices.Marshal]::SizeOf($PROCESS_BASIC_INFORMATION) 215 | $returnLength = New-Object Int 216 | $CallResult = [Ntdll]::NtQueryInformationProcess($ProcHandle, 0, [ref]$PROCESS_BASIC_INFORMATION, $PROCESS_BASIC_INFORMATION_Size, [ref]$returnLength) 217 | 218 | # PID & PEB address 219 | # echo "`n[?] PID $($PROCESS_BASIC_INFORMATION.UniqueProcessId)" 220 | if ($x32Architecture) { 221 | # echo "[+] PebBaseAddress: 0x$("{0:X8}" -f $PROCESS_BASIC_INFORMATION.PebBaseAddress.ToInt32())" 222 | } else { 223 | # echo "[+] PebBaseAddress: 0x$("{0:X16}" -f $PROCESS_BASIC_INFORMATION.PebBaseAddress.ToInt64())" 224 | } 225 | 226 | # Lazy PEB parsing 227 | $_PEB = New-Object _PEB 228 | $_PEB = $_PEB.GetType() 229 | $BufferOffset = $PROCESS_BASIC_INFORMATION.PebBaseAddress.ToInt64() 230 | $NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset 231 | $PEBFlags = [system.runtime.interopservices.marshal]::PtrToStructure($NewIntPtr, [type]$_PEB) 232 | 233 | # Take ownership of PEB 234 | # Not sure this is strictly necessary but why not! 235 | if ($x32Architecture) { 236 | [Ntdll]::RtlEnterCriticalSection($PEBFlags.FastPebLock32) 237 | } else { 238 | [Ntdll]::RtlEnterCriticalSection($PEBFlags.FastPebLock64) 239 | } # echo "[!] RtlEnterCriticalSection --> &Peb->FastPebLock" 240 | 241 | # &Peb->ProcessParameters->ImagePathName/CommandLine 242 | if ($x32Architecture) { 243 | # Offset to &Peb->ProcessParameters 244 | $PROCESS_PARAMETERS = $PEBFlags.ProcessParameters32.ToInt64() 245 | # x86 UNICODE_STRING struct's --> Size 8-bytes = (UInt16*2)+IntPtr 246 | [UInt32]$StructSize = 8 247 | $ImagePathName = $PROCESS_PARAMETERS + 0x38 248 | $CommandLine = $PROCESS_PARAMETERS + 0x40 249 | } else { 250 | # Offset to &Peb->ProcessParameters 251 | $PROCESS_PARAMETERS = $PEBFlags.ProcessParameters64.ToInt64() 252 | # x64 UNICODE_STRING struct's --> Size 16-bytes = (UInt16*2)+IntPtr 253 | [UInt32]$StructSize = 16 254 | $ImagePathName = $PROCESS_PARAMETERS + 0x60 255 | $CommandLine = $PROCESS_PARAMETERS + 0x70 256 | } 257 | 258 | # Overwrite PEB struct 259 | # Can easily be extended to other UNICODE_STRING structs in _RTL_USER_PROCESS_PARAMETERS(/or in general) 260 | $ImagePathNamePtr = New-Object System.Intptr -ArgumentList $ImagePathName 261 | $CommandLinePtr = New-Object System.Intptr -ArgumentList $CommandLine 262 | if ($x32Architecture) { 263 | # echo "[>] Overwriting &Peb->ProcessParameters.ImagePathName: 0x$("{0:X8}" -f $ImagePathName)" 264 | # echo "[>] Overwriting &Peb->ProcessParameters.CommandLine: 0x$("{0:X8}" -f $CommandLine)" 265 | } else { 266 | # echo "[>] Overwriting &Peb->ProcessParameters.ImagePathName: 0x$("{0:X16}" -f $ImagePathName)" 267 | # echo "[>] Overwriting &Peb->ProcessParameters.CommandLine: 0x$("{0:X16}" -f $CommandLine)" 268 | } 269 | Emit-UNICODE_STRING -hProcess $ProcHandle -lpBaseAddress $ImagePathNamePtr -dwSize $StructSize -data $BinPath 270 | Emit-UNICODE_STRING -hProcess $ProcHandle -lpBaseAddress $CommandLinePtr -dwSize $StructSize -data $BinPath 271 | 272 | # &Peb->Ldr 273 | $_PEB_LDR_DATA = New-Object _PEB_LDR_DATA 274 | $_PEB_LDR_DATA = $_PEB_LDR_DATA.GetType() 275 | if ($x32Architecture) { 276 | $BufferOffset = $PEBFlags.Ldr32.ToInt64() 277 | } else { 278 | $BufferOffset = $PEBFlags.Ldr64.ToInt64() 279 | } 280 | $NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset 281 | $LDRFlags = [system.runtime.interopservices.marshal]::PtrToStructure($NewIntPtr, [type]$_PEB_LDR_DATA) 282 | 283 | # &Peb->Ldr->InLoadOrderModuleList->Flink 284 | $_LDR_DATA_TABLE_ENTRY = New-Object _LDR_DATA_TABLE_ENTRY 285 | $_LDR_DATA_TABLE_ENTRY = $_LDR_DATA_TABLE_ENTRY.GetType() 286 | $BufferOffset = $LDRFlags.InLoadOrderModuleList.Flink.ToInt64() 287 | $NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset 288 | 289 | # Traverse doubly linked list 290 | # &Peb->Ldr->InLoadOrderModuleList->InLoadOrderLinks->Flink 291 | # This is probably overkill, powershell.exe should always be the first entry for InLoadOrderLinks 292 | # echo "[?] Traversing &Peb->Ldr->InLoadOrderModuleList doubly linked list" 293 | while ($ListIndex -ne $LDRFlags.InLoadOrderModuleList.Blink) { 294 | $LDREntry = [system.runtime.interopservices.marshal]::PtrToStructure($NewIntPtr, [type]$_LDR_DATA_TABLE_ENTRY) 295 | 296 | if ([System.Runtime.InteropServices.Marshal]::PtrToStringUni($LDREntry.FullDllName.Buffer) -like "*powershell.exe*") { 297 | 298 | if ($x32Architecture) { 299 | # x86 UNICODE_STRING struct's --> Size 8-bytes = (UInt16*2)+IntPtr 300 | [UInt32]$StructSize = 8 301 | $FullDllName = $BufferOffset + 0x24 302 | $BaseDllName = $BufferOffset + 0x2C 303 | } else { 304 | # x64 UNICODE_STRING struct's --> Size 16-bytes = (UInt16*2)+IntPtr 305 | [UInt32]$StructSize = 16 306 | $FullDllName = $BufferOffset + 0x48 307 | $BaseDllName = $BufferOffset + 0x58 308 | } 309 | 310 | # Overwrite _LDR_DATA_TABLE_ENTRY struct 311 | # Can easily be extended to other UNICODE_STRING structs in _LDR_DATA_TABLE_ENTRY(/or in general) 312 | $FullDllNamePtr = New-Object System.Intptr -ArgumentList $FullDllName 313 | $BaseDllNamePtr = New-Object System.Intptr -ArgumentList $BaseDllName 314 | if ($x32Architecture) { 315 | # echo "[>] Overwriting _LDR_DATA_TABLE_ENTRY.FullDllName: 0x$("{0:X8}" -f $FullDllName)" 316 | # echo "[>] Overwriting _LDR_DATA_TABLE_ENTRY.BaseDllName: 0x$("{0:X8}" -f $BaseDllName)" 317 | } else { 318 | # echo "[>] Overwriting _LDR_DATA_TABLE_ENTRY.FullDllName: 0x$("{0:X16}" -f $FullDllName)" 319 | # echo "[>] Overwriting _LDR_DATA_TABLE_ENTRY.BaseDllName: 0x$("{0:X16}" -f $BaseDllName)" 320 | } 321 | Emit-UNICODE_STRING -hProcess $ProcHandle -lpBaseAddress $FullDllNamePtr -dwSize $StructSize -data $BinPath 322 | Emit-UNICODE_STRING -hProcess $ProcHandle -lpBaseAddress $BaseDllNamePtr -dwSize $StructSize -data $BinPath 323 | } 324 | 325 | $ListIndex = $BufferOffset = $LDREntry.InLoadOrderLinks.Flink.ToInt64() 326 | $NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset 327 | } 328 | 329 | # Release ownership of PEB 330 | if ($x32Architecture) { 331 | [Ntdll]::RtlLeaveCriticalSection($PEBFlags.FastPebLock32) 332 | } else { 333 | [Ntdll]::RtlLeaveCriticalSection($PEBFlags.FastPebLock64) 334 | } # echo "[!] RtlLeaveCriticalSection --> &Peb->FastPebLock`n" 335 | } 336 | 337 | # Check all the variables are correct before starting 338 | if (!(Test-Path "$TargetFile")){ 339 | write-host "File not found. Exiting..."`r`n 340 | Break 341 | } 342 | 343 | # Set the arguments to the required verb actions 344 | if ($Action -eq "PIN"){$PinUnpin = "taskbarpin"} 345 | if ($Action -eq "UNPIN"){$PinUnpin = "taskbarunpin"} 346 | 347 | # Split the target path to folder, filename and filename with no extension 348 | $FileNameNoExt = (Get-ChildItem $TargetFile).BaseName 349 | $FileNameWithExt = (Get-ChildItem $TargetFile).Name 350 | $Directory = (Get-Childitem $TargetFile).Directory 351 | 352 | # Hide Powershell as Explorer... 353 | Masquerade-PEB -BinPath "C:\Windows\explorer.exe" 354 | 355 | # If target file is not a .lnk then create a shortcut, (un)pin that and then delete it 356 | if ((Get-ChildItem $TargetFile).Extension -ne ".lnk"){ 357 | 358 | if (test-path "$env:TEMP\$FileNameNoExt.lnk"){Remove-Item -path "$env:TEMP\$FileNameNoExt.lnk"} 359 | 360 | $WshShell = New-Object -comObject WScript.Shell 361 | $Shortcut = $WshShell.CreateShortcut("$env:TEMP\$FileNameNoExt.lnk") 362 | $Shortcut.TargetPath = $TargetFile 363 | $Shortcut.Save() 364 | 365 | $TargetFile = "$env:TEMP\$FileNameNoExt.lnk" 366 | $FileNameWithExt = (Get-ChildItem $TargetFile).Name 367 | $Directory = (Get-Childitem $TargetFile).Directory 368 | 369 | (New-Object -ComObject shell.application).Namespace("$Directory\").parsename("$FileNameWithExt").invokeverb("$PinUnpin") 370 | 371 | if (test-path "$env:TEMP\$FileNameNoExt.lnk"){Remove-Item -path "$env:TEMP\$FileNameNoExt.lnk"} 372 | 373 | } else { 374 | (New-Object -ComObject shell.application).Namespace("$Directory\").parsename("$FileNameWithExt").invokeverb("$PinUnpin") 375 | } 376 | 377 | } 378 | 379 | function UnPin-AppFromTaskBar { 380 | param ( 381 | $AppName 382 | ) 383 | $Apps = (New-Object -Com Shell.Application).NameSpace('shell:::{4234d49b-0245-4df3-b780-3893943456e1}').Items() 384 | ($Apps | where name -like "$AppName").invokeverb("taskbarunpin") 385 | } 386 | #Examples: 387 | # Unpin Mail App and Windows Store 388 | UnPin-AppFromTaskBar -AppName "Microsoft Store" -Verb taskbarunpin 389 | UnPin-AppFromTaskBar -AppName Mail -Verb taskbarunpin 390 | # Pin Chrome and Office Apps to taskbar 391 | $StartMenuFolder = "$env:programdata\Microsoft\Windows\Start Menu\Programs" 392 | Pin-ToTaskbar -targetfile "$StartMenuFolder\Google Chrome.lnk" -Action pin 393 | Pin-ToTaskbar -targetfile "$StartMenuFolder\Excel.lnk" -Action pin 394 | Pin-ToTaskbar -targetfile "$StartMenuFolder\Word.lnk" -Action pin 395 | Pin-ToTaskbar -targetfile "$StartMenuFolder\Outlook.lnk" -Action pin 396 | Pin-ToTaskbar -targetfile "$StartMenuFolder\Firefox.lnk" -Action pin 397 | 398 | 399 | -------------------------------------------------------------------------------- /Remove-LocalAdminPrivelageDETECTION.ps1: -------------------------------------------------------------------------------- 1 | # Proactive remediation detection script to determine if user is a local Administrator 2 | $group =[ADSI]"WinNT://$($env:COMPUTERNAME)/Administrators" 3 | $admins = @($group.Invoke("Members")) | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)} 4 | $user = ((gcim win32_computersystem).username -split '\\')[1] 5 | if ($admins -like $user) 6 | { 7 | Write-Host "User is Admin" 8 | exit 1 9 | } 10 | else 11 | { 12 | Write-Host "User is not Admin" 13 | exit 0 14 | } -------------------------------------------------------------------------------- /Remove-LocalAdminPrivelageREMEDIATION.ps1: -------------------------------------------------------------------------------- 1 | $group =[ADSI]"WinNT://$($env:COMPUTERNAME)/Administrators" 2 | $admins = @($group.Invoke("Members")) | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)} 3 | $user = ((gcim win32_computersystem).username -split '\\')[1] 4 | Net Localgroup Administrators /delete (gcim win32_computersystem).username 5 | 6 | $adminspost = @($group.Invoke("Members")) | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)} 7 | if ($adminspost -like $user) 8 | { 9 | Write-Host "User is Admin" 10 | exit 1 11 | } 12 | else 13 | { 14 | Write-Host "User is not Admin" 15 | exit 0 16 | } -------------------------------------------------------------------------------- /RemoveDuplicatedShortcuts_plustask.ps1: -------------------------------------------------------------------------------- 1 | #If you are enforcing One Drive Known File Move, redirecting the Desktop, its possible some shortcuts may be duplicated 2 | #between the time the computer enrolls in intune and one drive redirects the desktop. This script will create a 3 | #scheduled task to clear up and remove duplicated shortcuts if they exist at logon. 4 | #Just add in the shortcut name and your companies One Drive path. 5 | 6 | $dupe = '$UserSID = (New-Object -ComObject Microsoft.DiskQuota).TranslateLogonNameToSID((Get-WmiObject -Class Win32_ComputerSystem).Username) 7 | $Path = "HKLM\SOFTWARE\Microsoft\WIndows NT\CurrentVersion\Profilelist\$UserSID" 8 | $UserPath = Get-ItemProperty "Registry::$path" -name "ProfileImagePath" | select -ExpandProperty ProfileImagePath 9 | 10 | 11 | $duplicateshortcuts = "shortcut1.lnk","shortcut2.lnk","shortcut3.lnk" | foreach {test-path "$UserPath\OneDrive - YourCompany\Desktop\$_."} 12 | if ($duplicateshortcuts -eq $true) 13 | { 14 | $OldShortcuts = @("$UserPath\OneDrive - YourCompany\Desktop\shortcut1.lnk","$UserPath\OneDrive - YourCompany\Desktop\shortcut1.lnk.lnk","$UserPath\OneDrive - YourCompany\Desktop\shortcut3.lnk","$UserPath\OneDrive - YourCompany\Desktop\Microsoft Edge - Copy.lnk") 15 | Get-ChildItem $OldShortcuts | Remove-Item 16 | }' 17 | 18 | new-item c:\automation -ItemType directory -force 19 | set-content c:\automation\removedupshortcut.ps1 $dupe 20 | 21 | if( -Not (Get-ScheduledTask -TaskName "Remove Duplicate Shortcuts" -ErrorAction SilentlyContinue -OutVariable task) ) 22 | { 23 | $Params = @{ 24 | Action = (New-ScheduledTaskAction -Execute 'powershell' -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass C:\Automation\removedupshortcut.ps1') 25 | Trigger = (New-ScheduledTaskTrigger -AtLogOn) 26 | Principal = (New-ScheduledTaskPrincipal -GroupId "System") 27 | TaskName = 'Remove Duplicate Shortcuts' 28 | Description = 'Remove Duplicate Shortcuts' 29 | } 30 | Register-ScheduledTask @Params 31 | Start-ScheduledTask -TaskName "Remove Duplicate Shortcuts" 32 | } 33 | else 34 | { 35 | Start-ScheduledTask -TaskName "Remove Duplicate Shortcuts" 36 | } 37 | -------------------------------------------------------------------------------- /Volume_Shadow_Copy_Task.ps1: -------------------------------------------------------------------------------- 1 | ############## Set 3 daily Volume Shadow Copy Tasks ##################### 2 | 3 | if( -Not (Get-ScheduledTask -TaskName "Volume Shadow Copy C" -ErrorAction SilentlyContinue -OutVariable task) ) 4 | { 5 | $Params = @{ 6 | Action = (New-ScheduledTaskAction -Execute 'cmd' -Argument '/c /c "wmic shadowcopy call create Volume=c:\" ') 7 | Trigger = (New-ScheduledTaskTrigger -Daily -At 8am) 8 | Principal = (New-ScheduledTaskPrincipal -GroupId "System") 9 | TaskName = 'Volume Shadow Copy C' 10 | Description = 'Volume Shadow Copy C' 11 | } 12 | Register-ScheduledTask @Params 13 | Start-ScheduledTask -TaskName "Volume Shadow Copy C" 14 | } 15 | else 16 | { 17 | Start-ScheduledTask -TaskName "Volume Shadow Copy C" 18 | } 19 | 20 | if( -Not (Get-ScheduledTask -TaskName "Volume Shadow Copy C 2" -ErrorAction SilentlyContinue -OutVariable task) ) 21 | { 22 | $Params = @{ 23 | Action = (New-ScheduledTaskAction -Execute 'cmd' -Argument '/c /c "wmic shadowcopy call create Volume=c:\" ') 24 | Trigger = (New-ScheduledTaskTrigger -Daily -At 1PM) 25 | Principal = (New-ScheduledTaskPrincipal -GroupId "System") 26 | TaskName = 'Volume Shadow Copy C 2' 27 | Description = 'Volume Shadow Copy C 2' 28 | } 29 | Register-ScheduledTask @Params 30 | } 31 | 32 | if( -Not (Get-ScheduledTask -TaskName "Volume Shadow Copy C 3" -ErrorAction SilentlyContinue -OutVariable task) ) 33 | { 34 | $Params = @{ 35 | Action = (New-ScheduledTaskAction -Execute 'cmd' -Argument '/c /c "wmic shadowcopy call create Volume=c:\" ') 36 | Trigger = (New-ScheduledTaskTrigger -Daily -At 6PM) 37 | Principal = (New-ScheduledTaskPrincipal -GroupId "System") 38 | TaskName = 'Volume Shadow Copy C 3' 39 | Description = 'Volume Shadow Copy C 3' 40 | } 41 | Register-ScheduledTask @Params 42 | } 43 | 44 | ######## Set Max Shadow Copies 45 | 46 | New-ItemProperty registry::HKLM\System\CurrentControlSet\Services\VSS\Settings -Name MaxShadowCopies -PropertyType DWORD -Value 16 47 | 48 | ############# Resize Shadow Storage max size 49 | vssadmin resize shadowstorage /for=C: /maxsize=5GB -------------------------------------------------------------------------------- /Winget-InstallDetection.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 3/7/2022 2:14 PM 6 | Created by: Dave Just 7 | Organization: 8 | Filename: WingetInstallDetection.ps1 9 | =========================================================================== 10 | .DESCRIPTION 11 | Simple Win32App detection script. Detects the presence of an uninstall key matching the displayname of the variable $SoftwareName. 12 | If a key is matched, return to Intune that the software is installed. 13 | .EXAMPLE 14 | $SoftwareName = 'Chrome' # Search for an uninstall key with Displayname 'Chrome' for Google Chrome 15 | #> 16 | # Edit the software displayname below 17 | 18 | $SoftwareName = '' 19 | 20 | function Get-RegUninstallKey 21 | { 22 | param ( 23 | [string]$DisplayName 24 | ) 25 | $uninstallKeys = @( 26 | "registry::HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall" 27 | "registry::HKLM\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 28 | ) 29 | $LoggedOnUser = (Get-CimInstance -ClassName Win32_ComputerSystem).UserName 30 | if ($LoggedOnUser){ 31 | $UserSID = ([System.Security.Principal.NTAccount](Get-CimInstance -ClassName Win32_ComputerSystem).UserName).Translate([System.Security.Principal.SecurityIdentifier]).Value 32 | $UninstallKeys += @("registry::HKU\$UserSID\Software\Microsoft\Windows\CurrentVersion\Uninstall" , "registry::HKU\$UserSID\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall") 33 | } 34 | $softwareTable =@() 35 | foreach ($key in $uninstallKeys){ 36 | if (-Not (Test-Path $Key)){ 37 | Write-Warning "$Key not found" 38 | continue 39 | } 40 | $softwareTable += Get-Childitem $key | 41 | foreach { 42 | try { 43 | Get-ItemProperty $_.pspath | Where-Object { $_.displayname } | Sort-Object -Property displayname 44 | } 45 | catch [System.InvalidCastException] { 46 | # Ignore error as I was occasionally getting an invalid cast error on Get-ItemProperty 47 | } 48 | } 49 | } 50 | if ($DisplayName) 51 | { 52 | $softwareTable | Where-Object { $_.displayname -Like "*$DisplayName*" } 53 | } 54 | else 55 | { 56 | $softwareTable | Sort-Object -Property displayname -Unique 57 | } 58 | 59 | } 60 | 61 | $UninstallKey = Get-RegUninstallKey -DisplayName $SoftwareName 62 | if ($UninstallKey) 63 | { 64 | Write-Output "$($SoftwareName) is installed" 65 | exit 0 66 | } 67 | else 68 | { 69 | exit 1 70 | } 71 | -------------------------------------------------------------------------------- /Winget-InstallPackage.intunewin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djust270/Intune-Scripts/62f388a7c8116c4f8c975bcd27d6e883c60e75c5/Winget-InstallPackage.intunewin -------------------------------------------------------------------------------- /Winget-InstallPackage.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 3/7/2022 2:14 PM 6 | Created by: Dave Just 7 | Organization: 8 | Filename: Winget-InstallPackage.ps1 9 | 10 | Updated 07/15/2024 to support uninstallation, also handle scenario when WinGet is not installed 11 | but package installation is requested during autopilot / oobe without a user account. Moved log location 12 | to %programdata%\Microsoft\IntuneManagementExtension\Logs 13 | 14 | Updated 08/12/2024 to download and extract DesktopAppInstaller msixbundle to %ProgramData% if WinGet is not installed 15 | This allows WinGet to function in SYSTEM context during OOBE/Autopilot when installation under user context is not possbile. 16 | =========================================================================== 17 | .DESCRIPTION 18 | Installs any package within the WinGet public repository running as SYSTEM. Can be packaged and deployed as a Win32App in Intune 19 | Use as base for any install with WinGet. Simply specify the PackageID and log variables. 20 | 21 | If WinGet is not currently installed, a zipped copy will be extracted to the %PrograData% folder as installation in user context during OOBE/Autopilot was un-reliable. 22 | .PARAMETER PackageID 23 | Specify the WinGet ID. Use WinGet Search "SoftwareName" to locate the PackageID 24 | .PARAMETER PackageName 25 | Specify the Package Name in place of PackageID if preferred. 26 | .PARAMETER Mode 27 | Required parameter. Specify 'install' or 'uninstall' to perform that operation for the given package. 28 | .PARAMETER Log 29 | Required parameter. Specify the log file name. This will be logged to %programdata%\Microsoft\IntuneManagementExtension\Logs" 30 | .PARAMETER AdditionalInstallArgs 31 | Specify Additional Installation Arguments to pass to WinGet https://learn.microsoft.com/en-us/windows/package-manager/winget/install 32 | .EXAMPLE 33 | powershell.exe -executionpolicy bypass -file Winget-InstallPackage.ps1 -PackageID "Google.Chrome" -Log "ChromeWingetInstall.log" 34 | .EXAMPLE 35 | powershell.exe -executionpolicy bypass -file Winget-InstallPackage.ps1 -mode install -PackageID "Notepad++.Notepad++" -Log "NotepadPlusPlus.log" 36 | .EXAMPLE 37 | powershell.exe -executionpolicy bypass -file Winget-InstallPackage.ps1 -PackageID "Python.Python.3.11" -mode uninstall -Log "Python3Install.log" -AdditionalInstallArgs "--architecture x64" 38 | .EXAMPLE 39 | powershell.exe -executionpolicy bypass -file Winget-InstallPackage.ps1 -PackageName "Microsoft .NET Runtime 6.0" -mode install -Log "DotNetRuntime6.log" 40 | #> 41 | 42 | <# 43 | TODO: 44 | Add function to download zipped WinGet copy from blob storage in the event that WinGet is not installed 45 | Extract to %ProgramData% folder 46 | #> 47 | param ( 48 | [string]$PackageID = 'Notepad++.Notepad++', 49 | 50 | [string]$PackageName, 51 | 52 | [string]$AdditionalInstallArgs, 53 | 54 | [parameter()] 55 | [ValidateSet('Install','Uninstall')] 56 | # Set default mode to install 57 | [string]$Mode = 'Install', 58 | 59 | [parameter(Mandatory)] 60 | [string]$Log 61 | ) 62 | 63 | # Re-launch as 64bit process (source: https://z-nerd.com/blog/2020/03/31-intune-win32-apps-powershell-script-installer/) 64 | $argsString = "" 65 | If ($ENV:PROCESSOR_ARCHITEW6432 -eq "AMD64") 66 | { 67 | Try 68 | { 69 | foreach ($k in $MyInvocation.BoundParameters.keys) 70 | { 71 | switch ($MyInvocation.BoundParameters[$k].GetType().Name) 72 | { 73 | "SwitchParameter" { if ($MyInvocation.BoundParameters[$k].IsPresent) { $argsString += "-$k " } } 74 | "String" { $argsString += "-$k `"$($MyInvocation.BoundParameters[$k])`" " } 75 | "Int32" { $argsString += "-$k $($MyInvocation.BoundParameters[$k]) " } 76 | "Boolean" { $argsString += "-$k `$$($MyInvocation.BoundParameters[$k]) " } 77 | } 78 | } 79 | Start-Process -FilePath "$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -ArgumentList "-File `"$($PSScriptRoot)\Winget-InstallPackage.ps1`" $($argsString)" -Wait -NoNewWindow 80 | } 81 | Catch 82 | { 83 | Throw "Failed to start 64-bit PowerShell" 84 | } 85 | Exit 86 | } 87 | 88 | #region HelperFunctions 89 | 90 | function Write-Log($message) #Log script messages to temp directory 91 | { 92 | $LogMessage = ((Get-Date -Format "MM-dd-yy HH:MM:ss ") + $message) 93 | if (Test-Path "$env:programdata\Microsoft\IntuneManagementExtension\Logs") { 94 | Out-File -InputObject $LogMessage -FilePath "$env:programdata\Microsoft\IntuneManagementExtension\Logs\$Log" -Append -Encoding utf8 95 | } 96 | Write-Host $message 97 | } 98 | 99 | function Download-Winget { 100 | <# 101 | .SYNOPSIS 102 | Download Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle and extract contents with 7zip cli to %ProgramData% 103 | #> 104 | $ProgressPreference = 'SilentlyContinue' 105 | $7zipFolder = "${env:WinDir}\Temp\7zip" 106 | try { 107 | Write-Log "Downloading WinGet..." 108 | # Create staging folder 109 | New-Item -ItemType Directory -Path "${env:WinDir}\Temp\WinGet-Stage" -Force 110 | # Download Desktop App Installer msixbundle 111 | Invoke-WebRequest -UseBasicParsing -Uri https://aka.ms/getwinget -OutFile "${env:WinDir}\Temp\WinGet-Stage\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" 112 | } 113 | catch { 114 | Write-Log "Failed to download WinGet!" 115 | Write-Log $_.Exception.Message 116 | return 117 | } 118 | try { 119 | Write-Log "Downloading 7zip CLI executable..." 120 | # Create temp 7zip CLI folder 121 | New-Item -ItemType Directory -Path $7zipFolder -Force 122 | Invoke-WebRequest -UseBasicParsing -Uri https://www.7-zip.org/a/7zr.exe -OutFile "$7zipFolder\7zr.exe" 123 | Invoke-WebRequest -UseBasicParsing -Uri https://www.7-zip.org/a/7z2408-extra.7z -OutFile "$7zipFolder\7zr-extra.7z" 124 | Write-Log "Extracting 7zip CLI executable to ${7zipFolder}..." 125 | & "$7zipFolder\7zr.exe" x "$7zipFolder\7zr-extra.7z" -o"$7zipFolder" -y 126 | } 127 | catch { 128 | Write-Log "Failed to download 7zip CLI executable!" 129 | Write-Log $_.Exception.Message 130 | return 131 | } 132 | try { 133 | # Create Folder for DesktopAppInstaller inside %ProgramData% 134 | New-Item -ItemType Directory -Path "${env:ProgramData}\Microsoft.DesktopAppInstaller" -Force 135 | Write-Log "Extracting WinGet..." 136 | & "$7zipFolder\7za.exe" x "${env:WinDir}\Temp\WinGet-Stage\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -o"${env:WinDir}\Temp\WinGet-Stage" -y 137 | & "$7zipFolder\7za.exe" x "${env:WinDir}\Temp\WinGet-Stage\AppInstaller_x64.msix" -o"${env:ProgramData}\Microsoft.DesktopAppInstaller" -y 138 | } 139 | catch { 140 | Write-Log "Failed to extract WinGet!" 141 | Write-Log $_.Exception.Message 142 | return 143 | } 144 | if (-Not (Test-Path "${env:ProgramData}\Microsoft.DesktopAppInstaller\WinGet.exe")){ 145 | Write-Log "Failed to extract WinGet!" 146 | exit 1 147 | } 148 | $Script:WinGet = "${env:ProgramData}\Microsoft.DesktopAppInstaller\WinGet.exe" 149 | } 150 | 151 | function Install-VisualC { 152 | try { 153 | $downloadurl = 'https://aka.ms/vs/17/release/vc_redist.x64.exe' 154 | $WebClient = New-Object System.Net.WebClient 155 | $WebClient.DownloadFile($downloadurl, "$env:Temp\vc_redist.x64.exe") 156 | $WebClient.Dispose() 157 | } 158 | catch { 159 | Write-Log "Failed to download Visual C++!" 160 | Write-Log $_.Exception.Message 161 | } 162 | # Check if another installation is in progress, then wait for it to complete 163 | $MSIExecCheck = Get-Process | Where-Object {$_.processname -eq 'msiexec'} 164 | if ($Null -ne $MSIExecCheck){ 165 | Write-Log "another msi installation is in progress. Waiting for process to complete..." 166 | Wait-Process msiexec 167 | Write-Log "Continuing installation..." 168 | } 169 | try { 170 | $Install = start-process "$env:temp\vc_redist.x64.exe" -argumentlist "/q /norestart" -Wait -PassThru 171 | Write-Log "Installation completed with exit code $($Install.ExitCode)" 172 | return $Install.ExitCode 173 | } 174 | catch { 175 | Write-Log $_.Exception.Message 176 | } 177 | try { 178 | remove-item "$env:Temp\vc_redist.x64.exe" 179 | } 180 | catch { 181 | Write-Log "Failed to remove vc_redist.x64.exe after installation" 182 | } 183 | } 184 | 185 | function Get-RegUninstallKey 186 | { 187 | param ( 188 | [string]$DisplayName 189 | ) 190 | $uninstallKeys = @( 191 | "registry::HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall" 192 | "registry::HKLM\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 193 | ) 194 | $LoggedOnUser = (Get-CimInstance -ClassName Win32_ComputerSystem).UserName 195 | if ($LoggedOnUser){ 196 | $UserSID = ([System.Security.Principal.NTAccount](Get-CimInstance -ClassName Win32_ComputerSystem).UserName).Translate([System.Security.Principal.SecurityIdentifier]).Value 197 | $UninstallKeys += @("registry::HKU\$UserSID\Software\Microsoft\Windows\CurrentVersion\Uninstall" , "registry::HKU\$UserSID\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall") 198 | } 199 | $softwareTable =@() 200 | foreach ($key in $uninstallKeys){ 201 | if (-Not (Test-Path $Key)){ 202 | Write-Warning "$Key not found" 203 | continue 204 | } 205 | $softwareTable += Get-Childitem $key | 206 | ForEach-Object { 207 | try { 208 | Get-ItemProperty $_.pspath | Where-Object { $_.displayname } | Sort-Object -Property displayname 209 | } 210 | catch [System.InvalidCastException] { 211 | # Ignore error as I was occasionally getting an invalid cast error on Get-ItemProperty 212 | } 213 | } 214 | } 215 | if ($DisplayName) 216 | { 217 | $softwareTable | Where-Object { $_.displayname -Like "*$DisplayName*" } 218 | } 219 | else 220 | { 221 | $softwareTable | Sort-Object -Property displayname -Unique 222 | } 223 | 224 | } 225 | 226 | function WingetInstallPackage { 227 | param ( 228 | $PackageID, 229 | $PackageName, 230 | $AdditionalInstallArgs 231 | ) 232 | # Check if another msi install is in progress and wait 233 | 234 | $MSIExecCheck = Get-Process | Where-Object {$_.processname -eq 'msiexec'} 235 | if ($Null -ne $MSIExecCheck){ 236 | Write-Log "another msi installation is in progress. Waiting for process to complete..." 237 | Wait-Process msiexec 238 | Write-Log "Continuing installation..." 239 | } 240 | if ($PackageID){ 241 | & $Winget install --id $PackageID --source Winget --silent $AdditionalInstallArgs --accept-package-agreements --accept-source-agreements 242 | } 243 | elseif ($PackageName){ 244 | & $Winget install --name $PackageName --source Winget --silent $AdditionalInstallArgs --accept-package-agreements --accept-source-agreements 245 | } 246 | } 247 | 248 | function Resolve-WinGetPath { 249 | # Look for Winget install in WindowsApps folder 250 | $WinAppFolderPath = Get-ChildItem -path "$env:ProgramFiles/WindowsApps" -recurse -filter "winget.exe" | where {$_.VersionInfo.FileVersion -ge 1.23} 251 | if ($WinAppFolderPath){ 252 | $script:WinGet = $WinAppFolderPath | Select-Object -ExpandProperty Fullname | Sort-Object -Descending | Select-Object -First 1 253 | Write-Log "WinGet.exe found at path $Winget" 254 | } 255 | else { 256 | # Check if WinGet copy has already been extracted to ProgramData folder 257 | if (Test-Path "${env:ProgramData}\Microsoft.DesktopAppInstaller\WinGet.exe"){ 258 | Write-Log "WinGet.exe found in ${env:ProgramData}\Microsoft.DesktopAppInstaller}" 259 | $Script:WinGet = "${env:ProgramData}\Microsoft.DesktopAppInstaller\WinGet.exe" 260 | } 261 | else { 262 | # Download WinGet MSIX bundle and extract files to ProgramData folder 263 | Write-Log "WinGet.exe not found in ${env:ProgramData}\Microsoft.DesktopAppInstaller" 264 | Download-Winget 265 | } 266 | } 267 | } 268 | 269 | function Test-WinGetOutput { 270 | if (-Not (Test-Path $Winget)){ 271 | Write-Log "WinGet path not found at Test-WinGetOutput function!" 272 | Write-Log "WinGet variable : $WinGet" 273 | exit 1 274 | } 275 | $OutputTest = & $WinGet 276 | if ([string]::IsNullOrEmpty($OutputTest)){ 277 | Write-Log "WinGet executable test failed to produce output!" 278 | exit 1 279 | } 280 | } 281 | 282 | #endregion HelperFunctions 283 | #region Script 284 | 285 | $VisualC = Get-RegUninstallKey -DisplayName "Microsoft Visual C++ 2015-2022 Redistributable (x64)" 286 | 287 | # Get path for Winget executible 288 | Resolve-WinGetPath 289 | 290 | # If Visual C++ Redist. not installed, install it 291 | if (-Not $VisualC){ 292 | Write-Log -message "Visual C++ X64 not found. Attempting to install" 293 | try { 294 | $VisualCInstall = Install-VisualC 295 | } 296 | catch [System.InvalidOperationException]{ 297 | Write-Log -message "Error installing visual c++ redistributable. Attempting install once more" 298 | Start-Sleep -Seconds 30 299 | $VisualCInstall = Install-VisualC 300 | } 301 | catch { 302 | Write-Log -message "Failed to install visual c++ redistributable!" 303 | Write-Log -message $_ 304 | exit 1 305 | } 306 | if ($VisualCInstall -ne 0){ 307 | Write-Log -message "Visual C++ X64 install failed. Exit code : $VisualCInstall" 308 | exit 1 309 | } 310 | Test-WinGetOutput 311 | } 312 | try 313 | { 314 | switch ($Mode){ 315 | 'Install'{ 316 | if ($PackageID){ 317 | Write-Log -message "executing $Mode on $PackageID" 318 | $Install = WingetInstallPackage -PackageID $PackageID -AdditionalArgs $AdditionalInstallArgs 319 | } 320 | elseif ($PackageName){ 321 | Write-Log -message "executing $Mode on $PackageName" 322 | $Install = WingeInstallPackage -PackageName $PackageName -AdditionalArgs $AdditionalInstallArgs 323 | } 324 | Write-Log $Install 325 | } 326 | 'Uninstall'{ 327 | if ($PackageID){ 328 | Write-Log -message "executing $Mode on $PackageID" 329 | $Uninstall = & $Winget uninstall --id $PackageID --source WinGet --silent 330 | } 331 | elseif ($PackageName){ 332 | Write-Log -message "executing $Mode on $PackageName" 333 | $Uninstall = & $Winget uninstall --name $PackageName --source WinGet --silent 334 | 335 | } 336 | Write-Log $Uninstall 337 | } 338 | } 339 | } 340 | Catch 341 | { 342 | Write-Log $error[0] 343 | exit 1 344 | } 345 | #endregion 346 | -------------------------------------------------------------------------------- /Winget-InstallStorePackage-Detection.ps1: -------------------------------------------------------------------------------- 1 | $PackageID = '9WZDNCRFJB13' #Enter package ID here 2 | 3 | # DO NOT MODIFY ANYTHING BELOW 4 | # Leverage task scheduler to create a scheduled task as the logged on user 5 | # Task will export all installed packages to file using Winget 6 | winget export -o .\installedpackages.txt | out-null 7 | 8 | 9 | $PackageList = ".\installedpackages.txt" 10 | if (-Not (Test-Path $PackageList)){ 11 | Write-Host "Wignet package list not found!" 12 | exit 1 13 | } 14 | $InstalledPackages = Get-Content $PackageList | ConvertFrom-Json 15 | $IsInstalled = ($InstalledPackages).sources.packages | Where-Object {$_.packageidentifier -eq $PackageID} 16 | if ($IsInstalled){ 17 | Write-Host $PackageID " was detected!" 18 | remove-item $PackageList 19 | #exit 0 20 | } 21 | else { 22 | remove-item $PackageList 23 | #exit 1 24 | } -------------------------------------------------------------------------------- /Winget-InstallStorePackage.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 12/6/2022 2:14 PM 6 | Created by: Dave Just 7 | Organization: 8 | Filename: Winget-InstallStorePackage.ps1 9 | =========================================================================== 10 | .DESCRIPTION 11 | Installs any package from the MSStore. You must run this as the logged on user! 12 | Can be packaged and deployed as a Win32App in Intune. 13 | Use as base for any install with WinGet. Simply specify the PackageID and log variables. 14 | .PARAMETER PackageID 15 | Specify the WinGet ID. Use WinGet Search "SoftwareName" to locate the PackageID 16 | .EXAMPLE 17 | powershell.exe -executionpolicy bypass -file Winget-InstallStorePackage.ps1 -PackageID "9WZDNCRFJB13" -Log "FreshPaintWingetInstall.log" 18 | #> 19 | param ( 20 | $PackageID, 21 | $Log 22 | ) 23 | 24 | # Re-launch as 64bit process (source: https://z-nerd.com/blog/2020/03/31-intune-win32-apps-powershell-script-installer/) 25 | $argsString = "" 26 | If ($ENV:PROCESSOR_ARCHITEW6432 -eq "AMD64") 27 | { 28 | Try 29 | { 30 | foreach ($k in $MyInvocation.BoundParameters.keys) 31 | { 32 | switch ($MyInvocation.BoundParameters[$k].GetType().Name) 33 | { 34 | "SwitchParameter" { if ($MyInvocation.BoundParameters[$k].IsPresent) { $argsString += "-$k " } } 35 | "String" { $argsString += "-$k `"$($MyInvocation.BoundParameters[$k])`" " } 36 | "Int32" { $argsString += "-$k $($MyInvocation.BoundParameters[$k]) " } 37 | "Boolean" { $argsString += "-$k `$$($MyInvocation.BoundParameters[$k]) " } 38 | } 39 | } 40 | Start-Process -FilePath "$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -ArgumentList "-File `"$($PSScriptRoot)\Winget-InstallStorePackage.ps1`" $($argsString)" -Wait -NoNewWindow 41 | } 42 | Catch 43 | { 44 | Throw "Failed to start 64-bit PowerShell" 45 | } 46 | Exit 47 | } 48 | 49 | #region HelperFunctions 50 | 51 | 52 | function Install-WinGet # Adapted from https://github.com/microsoft/winget-pkgs/blob/master/Tools/SandboxTest.ps1 (better than my original code!) 53 | # This function will install the latest version of WinGet and its dependancies 54 | { 55 | $tempFolderName = 'WinGetInstall' 56 | $tempFolder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath $tempFolderName 57 | New-Item $tempFolder -ItemType Directory -ErrorAction SilentlyContinue | Out-Null 58 | 59 | $apiLatestUrl = if ($Prerelease) { 'https://api.github.com/repos/microsoft/winget-cli/releases?per_page=1' } 60 | else { 'https://api.github.com/repos/microsoft/winget-cli/releases/latest' } 61 | 62 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 63 | $WebClient = New-Object System.Net.WebClient 64 | 65 | function Get-LatestUrl 66 | { 67 | ((Invoke-WebRequest $apiLatestUrl -UseBasicParsing | ConvertFrom-Json).assets | Where-Object { $_.name -match '^Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle$' }).browser_download_url 68 | } 69 | 70 | function Get-LatestHash 71 | { 72 | $shaUrl = ((Invoke-WebRequest $apiLatestUrl -UseBasicParsing | ConvertFrom-Json).assets | Where-Object { $_.name -match '^Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.txt$' }).browser_download_url 73 | 74 | $shaFile = Join-Path -Path $tempFolder -ChildPath 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.txt' 75 | $WebClient.DownloadFile($shaUrl, $shaFile) 76 | 77 | Get-Content $shaFile 78 | } 79 | 80 | $desktopAppInstaller = @{ 81 | fileName = 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle' 82 | url = $(Get-LatestUrl) 83 | hash = $(Get-LatestHash) 84 | } 85 | 86 | $vcLibsUwp = @{ 87 | fileName = 'Microsoft.VCLibs.x64.14.00.Desktop.appx' 88 | url = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx' 89 | hash = '9BFDE6CFCC530EF073AB4BC9C4817575F63BE1251DD75AAA58CB89299697A569' 90 | } 91 | $uiLibsUwp = @{ 92 | fileName = 'Microsoft.UI.Xaml.2.7.zip' 93 | url = 'https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.0' 94 | hash = '422FD24B231E87A842C4DAEABC6A335112E0D35B86FAC91F5CE7CF327E36A591' 95 | } 96 | 97 | $dependencies = @($desktopAppInstaller, $vcLibsUwp, $uiLibsUwp) 98 | 99 | Write-Host '--> Checking dependencies' 100 | 101 | foreach ($dependency in $dependencies) 102 | { 103 | $dependency.file = Join-Path -Path $tempFolder -ChildPath $dependency.fileName 104 | #$dependency.pathInSandbox = (Join-Path -Path $tempFolderName -ChildPath $dependency.fileName) 105 | 106 | # Only download if the file does not exist, or its hash does not match. 107 | if (-Not ((Test-Path -Path $dependency.file -PathType Leaf) -And $dependency.hash -eq $(Get-FileHash $dependency.file).Hash)) 108 | { 109 | Write-Host @" 110 | - Downloading: 111 | $($dependency.url) 112 | "@ 113 | 114 | try 115 | { 116 | $WebClient.DownloadFile($dependency.url, $dependency.file) 117 | } 118 | catch 119 | { 120 | #Pass the exception as an inner exception 121 | throw [System.Net.WebException]::new("Error downloading $($dependency.url).", $_.Exception) 122 | } 123 | if (-not ($dependency.hash -eq $(Get-FileHash $dependency.file).Hash)) 124 | { 125 | throw [System.Activities.VersionMismatchException]::new('Dependency hash does not match the downloaded file') 126 | } 127 | } 128 | } 129 | 130 | # Extract Microsoft.UI.Xaml from zip (if freshly downloaded). 131 | # This is a workaround until https://github.com/microsoft/winget-cli/issues/1861 is resolved. 132 | 133 | if (-Not (Test-Path (Join-Path -Path $tempFolder -ChildPath \Microsoft.UI.Xaml.2.7\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx))) 134 | { 135 | Expand-Archive -Path $uiLibsUwp.file -DestinationPath ($tempFolder + '\Microsoft.UI.Xaml.2.7') -Force 136 | } 137 | $uiLibsUwp.file = (Join-Path -Path $tempFolder -ChildPath \Microsoft.UI.Xaml.2.7\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx) 138 | Add-AppxPackage -Path $($desktopAppInstaller.file) -DependencyPath $($vcLibsUwp.file), $($uiLibsUwp.file) 139 | # Clean up files 140 | Remove-Item $tempFolder -recurse -force 141 | } 142 | 143 | #endregion HelperFunctions 144 | #region Install 145 | Start-Transcript -Path "C:\logs\$Log" 146 | #Test if Winget is installed. If not, try and install it. 147 | try { 148 | WinGet | Out-Null 149 | } 150 | catch { 151 | Install-WinGet 152 | } 153 | try { 154 | Winget | Out-Null 155 | } 156 | Catch { 157 | Write-Host "Winget not found after attempting to install. Stopping operation" 158 | exit 1 159 | } 160 | 161 | Winget install --id $PackageID --source msstore --silent --accept-package-agreements --accept-source-agreements 162 | Stop-Transcript 163 | #endregion 164 | -------------------------------------------------------------------------------- /Winget-UpgradeSelect.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 1/18/2022 8:39 AM 6 | Created by: Dave Just 7 | Organization: 8 | Filename: Winget-UpgradeSelect.ps1 9 | =========================================================================== 10 | .DESCRIPTION 11 | Use the Windows Package Manager (Winget) to selectively install application updates. Edit the WinGetApprovedPackages hashtables with the packages 12 | you would like to keep updated 13 | #> 14 | param ( 15 | [string]$ClientName 16 | ) 17 | $LogName = 'WinGetPackageUpgrade' 18 | $LogDate = (Get-Date).ToFileTime() 19 | $Log = "$LogName-$LogDate.log" 20 | $results = [System.Collections.Generic.List[PsObject]]::new() 21 | $loggedOnUser = (GCIM Win32_ComputerSystem).Username 22 | 23 | #region HelperFunctions 24 | 25 | function Get-RegUninstallKey #List all system-wide installed software 26 | { 27 | param ( 28 | [string]$DisplayName 29 | ) 30 | $ErrorActionPreference = 'SilentlyContinue' 31 | $UserSID = ([System.Security.Principal.NTAccount](Get-CimInstance -ClassName Win32_ComputerSystem).UserName).Translate([System.Security.Principal.SecurityIdentifier]).Value 32 | $uninstallKeys = "registry::HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall", "registry::HKLM\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 33 | $softwareTable = @() 34 | 35 | foreach ($key in $uninstallKeys) 36 | { 37 | $softwareTable += Get-Childitem $key | Get-ItemProperty | where displayname | Sort-Object -Property displayname 38 | } 39 | if ($DisplayName) 40 | { 41 | $softwareTable | where displayname -Like "*$DisplayName*" 42 | } 43 | else 44 | { 45 | $softwareTable | Sort-Object -Unique 46 | } 47 | Return $softwareTable 48 | 49 | } 50 | 51 | function LogWrite($message) #Log script messages 52 | { 53 | $LogMessage = ((Get-Date -Format "MM-dd-yy HH:MM:ss ") + $message) 54 | Out-File -InputObject $message -FilePath "$env:TEMP\$Log" -Append -Encoding utf8 55 | #[System.IO.File]::AppendAllText("$env:TEMP\$Log","`n $($LogMessage)") 56 | } 57 | 58 | function InstallWinget # Install WinGet as logged on user 59 | { 60 | $script = @' 61 | $hasPackageManager = Get-AppPackage -name "Microsoft.DesktopAppInstaller" 62 | 63 | if(!$hasPackageManager) 64 | { 65 | $releases_url = "https://api.github.com/repos/microsoft/winget-cli/releases/latest" 66 | 67 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 68 | $releases = Invoke-RestMethod -uri "$($releases_url)" 69 | $latestRelease = $releases.assets | Where { $_.browser_download_url.EndsWith("msixbundle") } | Select -First 1 70 | 71 | Add-AppxPackage -Path $latestRelease.browser_download_url 72 | } 73 | '@ 74 | if (!(test-path C:\automation)) { mkdir C:\automation } 75 | $script | out-file C:\automation\script.ps1 76 | $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-executionpolicy bypass -file C:\automation\script.ps1" 77 | $trigger = New-ScheduledTaskTrigger -AtLogOn 78 | $principal = New-ScheduledTaskPrincipal -UserId (Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -expand UserName) 79 | $task = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal 80 | Register-ScheduledTask RunScript -InputObject $task 81 | Start-ScheduledTask -TaskName RunScript 82 | Start-Sleep -Seconds 2 83 | Unregister-ScheduledTask -TaskName RunScript -Confirm:$false 84 | Remove-Item C:\automation\script.ps1 85 | 86 | # Get path for Winget executible 87 | $Global:Winget = gci "C:\Program Files\WindowsApps" -Recurse -File | where {$_.name -like "AppInstallerCLI.exe" -or $_.name -like "WinGet.exe"} | select -ExpandProperty fullname 88 | 89 | # If there are multiple versions, select latest 90 | if ($Winget.count -gt 1){$Winget = $Winget[-1]} 91 | if (!($Winget)){LogWrite "AppInstallerCLI.exe not found after InstallWinget function. Aborting!" 92 | Write-Output "AppInstallerCLI.exe not found after InstallWinget function. Aborting!" 93 | Exit 1} 94 | 95 | } 96 | 97 | 98 | #endregion HelperFunctions 99 | 100 | #region Script 101 | 102 | 103 | # Get path for Winget executible 104 | $Winget = gci "C:\Program Files\WindowsApps" -Recurse -File | where {$_.name -like "AppInstallerCLI.exe" -or $_.name -like "WinGet.exe"} | select -ExpandProperty fullname 105 | # If there are multiple versions, select latest 106 | if ($Winget.count -gt 1){$Winget = $Winget[-1]} 107 | $WingetTemp = gci $env:TEMP -Recurse -File | where name -like AppInstallerCLI.exe | select -ExpandProperty fullname 108 | # Try to install Winget if not already installed 109 | if (!($Winget)) 110 | { 111 | if ($WingetTemp) { LogWrite "Winget found in $($env:TEMP)";$Winget = $WingetTemp } 112 | elseif ($loggedOnUser) { InstallWinget } 113 | else 114 | { 115 | try 116 | { 117 | 118 | LogWrite "Winget not found, attempting to download now to $($env:TEMP)" 119 | $WebClient = New-Object System.Net.WebClient 120 | $WebClient.DownloadFile('https://djstorage2.blob.core.windows.net/scriptsupport/WinGet.zip', "$env:Temp\WinGet.zip") 121 | $WebClient.Dispose() 122 | Expand-Archive $env:TEMP\WinGet.zip -destination $Env:Temp 123 | $Winget = "$Env:TEMP\WinGet\AppInstallerCLI.exe" 124 | } 125 | Catch 126 | { 127 | LogWrite "Unable to initialize Winget. Exiting" 128 | Write-Output $Error[0] 129 | exit 1 130 | } 131 | } 132 | 133 | } 134 | 135 | $Winrar = (Get-RegUninstallKey | where displayname -Like "*WinRAR*" | select -ExpandProperty Displayname) 136 | if (!($Winrar)) { $Winrar = "Null-1" } 137 | $7Zip = (Get-RegUninstallKey | where displayname -Like "*7-zip*" | select -ExpandProperty Displayname) 138 | if (!($7zip)) { $7zip = "Null-2" } 139 | 140 | # Hash table to translate installed software to Winget Package IDs 141 | $WinGetApprovedPackages = @{ 142 | 'Google Chrome' = 'Google.Chrome' 143 | 'Mozilla Firefox (x64 en-US)' = 'Mozilla.Firefox' 144 | 'Microsoft OneDrive' = 'Microsoft.OneDrive' 145 | 'Notepad++' = 'Notepad++.Notepad++' 146 | 'Microsoft Edge' = 'Microsoft.Edge' 147 | 'Lenovo System Update' = 'Lenovo.SystemUpdate' 148 | "$($7Zip)" = '7zip.7zip' 149 | "$($WinRar)" = 'RARLab.WinRAR' 150 | "Adobe Acrobat Reader DC" = 'Adobe.Acrobat.Reader.32-bit' 151 | "CCleaner" = "Piriform.CCleaner" 152 | "PuTTY" = "PuTTY.PuTTY" 153 | } 154 | 155 | $InstalledSoftware = Get-RegUninstallKey 156 | $UpgradeList = foreach ($Package in $WinGetApprovedPackages.Keys) { $InstalledSoftware | where displayname -Like $Package } 157 | 158 | LogWrite "Client: $($ClientName)" 159 | LogWrite "Hostname: $($env:COMPUTERNAME)" 160 | LogWrite "Found the following installed packages:" 161 | $UpgradeList | foreach {LogWrite "Name: $($_.Displayname) Version: $($_.DisplayVersion)"} 162 | 163 | # Index software displaynames in hash table 164 | $WingetPackages = $WinGetApprovedPackages[$UpgradeList.DisplayName] 165 | 166 | # Remove null values from array 167 | $WingetPackages = $WinGetPackages | where { $_ } 168 | 169 | # Run the upgrade command for installed software only based on our package list 170 | foreach ($Package in $WinGetPackages) 171 | { 172 | LogWrite "Upgrading $($Package)" 173 | try 174 | { 175 | $UpgradeRun = & $Winget upgrade --id $Package -h --accept-package-agreements --accept-source-agreements | Tee-Object "$env:TEMP\$log" -Append 176 | } 177 | Catch 178 | { 179 | LogWrite $Error[0] 180 | Write-Output $Error[0] 181 | } 182 | 183 | } 184 | # Adding Hashtable here again as 7zip and Winrar have the version number in the displayname 185 | # Need the new displayname to compare to the old 186 | 187 | $Winrar = (Get-RegUninstallKey | where displayname -Like "*WinRAR*" | select -ExpandProperty Displayname) 188 | if (!($Winrar)) { $Winrar = "Null-1" } 189 | $7Zip = (Get-RegUninstallKey | where displayname -Like "*7-zip*" | select -ExpandProperty Displayname) 190 | if (!($7zip)) { $7zip = "Null-2" } 191 | 192 | # Hash table to translate installed software to Winget Package IDs 193 | $WinGetApprovedPackages = @{ 194 | 'Google Chrome' = 'Google.Chrome' 195 | 'Mozilla Firefox (x64 en-US)' = 'Mozilla.Firefox' 196 | 'Microsoft OneDrive' = 'Microsoft.OneDrive' 197 | 'Notepad++' = 'Notepad++.Notepad++' 198 | 'Microsoft Edge' = 'Microsoft.Edge' 199 | 'Lenovo System Update' = 'Lenovo.SystemUpdate' 200 | "$($7Zip)" = '7zip.7zip' 201 | "$($WinRar)" = 'RARLab.WinRAR' 202 | "Adobe Acrobat Reader DC" = 'Adobe.Acrobat.Reader.32-bit' 203 | "CCleaner" = "Piriform.CCleaner" 204 | "PuTTY" = "PuTTY.PuTTY" 205 | } 206 | 207 | 208 | 209 | $InstalledSoftware = Get-RegUninstallKey 210 | $PostUpgradeList = foreach ($Package in $WinGetApprovedPackages.Keys) { $InstalledSoftware | where displayname -Like $Package } 211 | 212 | #Compare results 213 | $UpgradeListHash = @{ } 214 | $PostUpgradeHash = @{ } 215 | foreach ($i in $UpgradeList) { $UpgradeListHash.Add($i.displayname , $i.displayversion) } 216 | foreach ($i in $PostUpgradeList) { $PostUpgradeHash.Add($i.displayversion, $i.displayname) } 217 | $compare = Compare-Object $UpgradeList.displayversion -DifferenceObject $PostUpgradeList.displayversion | where sideindicator -eq "=>" | select -ExpandProperty InputObject 218 | if ($compare) { $UpgradedSoftware = $PostUpgradeHash[$compare] } 219 | 220 | # Log what software was updated and create custom object 221 | if (!($UpgradedSoftware)) 222 | { 223 | LogWrite "No software was eligable for upgrade" 224 | } 225 | 226 | else{ 227 | foreach ($i in $compare) 228 | { 229 | $SoftwareName = $PostUpgradeHash[$i] 230 | if ($SoftwareName -match "7-Zip*") 231 | { 232 | $OldVersion = $UpgradeList | where displayname -Like "7-zip*" | select -ExpandProperty displayversion 233 | } 234 | elseif ($SoftwareName -match "WinRAR*") 235 | { 236 | $OldVersion = $UpgradeList | where displayname -Like "WinRAR*" | select -ExpandProperty displayversion 237 | } 238 | else { $OldVersion = $UpgradeListHash[$SoftwareName] } 239 | LogWrite "$($SoftwareName) was upgraded to version $($i) from version $($OldVersion)" 240 | $results = [pscustomobject]@{ 241 | Computername = hostname 242 | Client = $ClientName 243 | UpgradedSoftware = $SoftwareName 244 | NewVersion = $i 245 | OldVersion = $OldVersion 246 | Time = (get-date -Format MM-dd_HH:m:ss.ff) 247 | } 248 | function ResultToAzureTable 249 | { 250 | $header = @{ 'Content-Type' = "application/json" } 251 | $flow = 'https://prod-126.westus.logic.azure.com:443/workflows/*' #URI for Power Automate Flow 252 | $flowheader = $results | ConvertTo-Json -Compress 253 | try 254 | { 255 | Invoke-RestMethod -Method Post -Body $flowheader -uri $flow -Headers $header -ErrorAction 'Stop' 256 | LogWrite "POST to Azure Table Successful!" 257 | } 258 | Catch 259 | { 260 | LogWrite "Error logging to Azure Table"; $global:RESTFailure = $true 261 | } 262 | Start-Sleep 2 263 | } 264 | ResultToAzureTable 265 | 266 | if ($RESTFailure){ResultToAzureTable} #Attempt to send REST POST to Azure table a second time 267 | 268 | } 269 | } 270 | 271 | Get-Content $env:TEMP\$Log #Write Log to Console 272 | #endregion Script 273 | 274 | -------------------------------------------------------------------------------- /WingetUpgrade-ProactiveDetection.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 8/22/2022 3:08 PM 6 | Created by: David Just 7 | Website: davidjust.com 8 | Filename: WingetUpgrade-ProactiveDetection.ps1 9 | =========================================================================== 10 | .DESCRIPTION 11 | Proactive Remediation detection script for applications with updates 12 | #> 13 | 14 | $Blacklisted = @( 15 | 'Microsoft.Teams' 16 | 'Microsoft.Office' 17 | 'Microsoft.VC++2015-2022Redist-x64' 18 | ) 19 | Import-Module -Name WingetTools 20 | $AvailableUpdates = Get-WGInstalled | where-object { $_.id -notin $Blacklisted -and $_.update } 21 | 22 | if ($AvailableUpdates.count -gt 0) 23 | { 24 | "There are applications with Updates available" 25 | $AvailableUpdates | Select-Object -Property Name, ID, InstalledVersion, OnlineVersion 26 | exit 1 27 | } 28 | else 29 | { 30 | "There are no apps to update" 31 | Exit 0 32 | } 33 | 34 | -------------------------------------------------------------------------------- /WingetUpgrade-Remediation.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 8/22/2022 10:46 AM 6 | Created by: David Just 7 | Website: david.just.com 8 | Filename: WingetUpgrade-Remediation.ps1 9 | =========================================================================== 10 | .DESCRIPTION 11 | A description of the file. 12 | #> 13 | function Write-Log($message) #Log script messages to temp directory 14 | { 15 | $LogMessage = ((Get-Date -Format "MM-dd-yy HH:MM:ss ") + $message) 16 | Out-File -InputObject $LogMessage -FilePath "$LogPath\$Log" -Append -Encoding utf8 17 | } 18 | 19 | $LogName = 'WinGetPackageUpgrade' 20 | $LogDate = Get-Date -Format dd-MM-yy_HH-mm # go with the EU format day / month / year 21 | $Log = "$LogName-$LogDate.log" 22 | $LogPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs" 23 | Import-Module WingetTools 24 | $WingetPath = Get-WGPath 25 | 26 | # Add any apps you do not wish to get updated here (for instance apps that auto-update). Use the Winget ID 27 | $Blacklisted = @( 28 | 'Microsoft.Teams' 29 | 'Microsoft.Office' 30 | 'Microsoft.VC++2015-2022Redist-x64' 31 | ) 32 | $AvailableUpdates = Get-WGInstalled | where-object { $_.id -notin $Blacklisted -and $_.update } 33 | Write-Log -message "Packages with Updates Available:" 34 | $AvailableUpdates | select Name, Version | Out-File -FilePath "$logpath\$Log" -Append -Encoding utf8 35 | 36 | 37 | foreach ($App in $AvailableUpdates) # Invoke upgrade for each updatable app and log results 38 | { 39 | [void](Get-Process | Where-Object { $_.name -Like "*$App.Name*" } | Stop-Process -Force) 40 | $UpgradeRun = & $WingetPath upgrade --id $App.id -h --accept-package-agreements --accept-source-agreements 41 | $UpgradeRun | Out-File -FilePath "$logpath\$log" -Append -Encoding utf8 42 | $Status = [bool]($UpgradeRun | select-string -SimpleMatch "Successfully installed") 43 | if ($Status -eq $true) 44 | { 45 | $Success += $App 46 | } 47 | else 48 | { 49 | $Failed += $App 50 | } 51 | 52 | } 53 | 54 | 55 | if ($Success.count -gt 0) 56 | { 57 | Write-Log -message "Successful Upgraded the following:" 58 | $Success | Out-File -FilePath "$logpath\$log" -Append -Encoding utf8 59 | "Sucessfully Updated the following apps:`n{0}" -f $($Success | Select-Object -Property name) 60 | } 61 | 62 | if ($Failed.count -gt 0) 63 | { 64 | Write-Log -message "Failed to Upgrade the following:" 65 | $Failed | Out-File -FilePath "$logpath\$log" -Append -Encoding utf8 66 | } 67 | 68 | # Cleanup any logfiles 14 days old or older 69 | $Limit = (Get-Date).AddDays(-14) 70 | $OldLogs = Get-ChildItem $logpath | Where-Object {$_.name -like "WingetPackageUpgrade*.log" -and ($Limit - $_.CreationTime).days -ge 14 } 71 | $OldLogs | Foreach-Object { Remove-Item -FilePath $_.FullName } 72 | -------------------------------------------------------------------------------- /WingetUpgradeTask.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | =========================================================================== 4 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 5 | Created on: 8/23/2022 8:30 AM 6 | Created by: David Just 7 | Website: davidjust.com 8 | Filename: WingetDailyUpgradeTask.ps1 9 | =========================================================================== 10 | .DESCRIPTION 11 | Create a scheduled task running as System to update applications daily using WinGet. 12 | #> 13 | 14 | $script = @' 15 | <# 16 | .NOTES 17 | =========================================================================== 18 | Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.195 19 | Created on: 8/22/2022 10:46 AM 20 | Created by: David Just 21 | Website: david.just.com 22 | Filename: WingetUpgrade-Remediation.ps1 23 | =========================================================================== 24 | .DESCRIPTION 25 | A description of the file. 26 | #> 27 | function Write-Log($message) #Log script messages to temp directory 28 | { 29 | $LogMessage = ((Get-Date -Format "MM-dd-yy HH:MM:ss ") + $message) 30 | Out-File -InputObject $LogMessage -FilePath "$LogPath\$Log" -Append -Encoding utf8 31 | } 32 | 33 | $LogName = 'WinGetPackageUpgrade' 34 | $LogDate = Get-Date -Format dd-MM-yy_HH-mm # go with the EU format day / month / year 35 | $Log = "$LogName-$LogDate.log" 36 | $LogPath = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs" 37 | Import-Module WingetTools 38 | $WingetPath = Get-WGPath 39 | 40 | # Add any apps you do not wish to get updated here (for instance apps that auto-update). Use the Winget ID 41 | $Blacklisted = @( 42 | 'Microsoft.Teams' 43 | 'Microsoft.Office' 44 | 'Microsoft.VC++2015-2022Redist-x64' 45 | ) 46 | $AvailableUpdates = Get-WGInstalled | where-object { $_.id -notin $Blacklisted -and $_.update } 47 | Write-Log -message "Packages with Updates Available:" 48 | $AvailableUpdates | select Name, Version | Out-File -FilePath "$logpath\$Log" -Append -Encoding utf8 49 | 50 | 51 | foreach ($App in $AvailableUpdates) # Invoke upgrade for each updatable app and log results 52 | { 53 | [void](Get-Process | Where-Object { $_.name -Like "*$App.Name*" } | Stop-Process -Force) 54 | $UpgradeRun = & $WingetPath upgrade --id $App.id -h --accept-package-agreements --accept-source-agreements 55 | $UpgradeRun | Out-File -FilePath "$logpath\$log" -Append -Encoding utf8 56 | $Status = [bool]($UpgradeRun | select-string -SimpleMatch "Successfully installed") 57 | if ($Status -eq $true) 58 | { 59 | $Success += $App 60 | } 61 | else 62 | { 63 | $Failed += $App 64 | } 65 | 66 | } 67 | 68 | 69 | if ($Success.count -gt 0) 70 | { 71 | Write-Log -message "Successful Upgraded the following:" 72 | $Success | Out-File -FilePath "$logpath\$log" -Append -Encoding utf8 73 | "Sucessfully Updated the following apps:`n{0}" -f $($Success | Select-Object -Property name) 74 | } 75 | 76 | if ($Failed.count -gt 0) 77 | { 78 | Write-Log -message "Failed to Upgrade the following:" 79 | $Failed | Out-File -FilePath "$logpath\$log" -Append -Encoding utf8 80 | } 81 | 82 | '@ 83 | if (!(test-path "$env:SystemDrive\automation")) { mkdir "$env:SystemDrive\automation" } 84 | $script | out-file -FilePath "$env:SystemDrive\automation\WingetAutomatedUpgrade.ps1" 85 | $Action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-executionpolicy bypass -file %SystemDrive%\automation\WingetAutomatedUpgrade.ps1 -windowstyle hidden" 86 | # Edit the schedule variable to adjust the desired schedule. 87 | # Weekly schedule example : $Schedule = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 6AM 88 | $Schedule = New-ScheduledTaskTrigger -Daily -At 6am 89 | $principal = New-ScheduledTaskPrincipal -UserId "NT Authority\SYSTEM" -RunLevel Highest 90 | $Settings = New-ScheduledTaskSettingsSet 91 | $Settings.DisallowStartIfOnBatteries = $false 92 | $Settings.StopIfGoingOnBatteries = $false 93 | $Settings.IdleSettings.StopOnIdleEnd = $false 94 | $CreateTask = New-ScheduledTask -Action $Action -Trigger $Schedule -Principal $principal -Settings $Settings 95 | Register-ScheduledTask "Winget Automated Upgrade Task" -InputObject $CreateTask 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /chromebookmarks.ps1: -------------------------------------------------------------------------------- 1 | $jsonRepresentation = '{ 2 | "checksum": "8a83fd48cdea66f88b0dcf708bceae47", 3 | "roots": { 4 | "bookmark_bar": { 5 | "children": [ { 6 | "date_added": "13218554400308142", 7 | "guid": "278dff65-0d68-4b8d-9cf8-60ea3b2dbe9d", 8 | "id": "5", 9 | "name": "Amazon", 10 | "type": "url", 11 | "url": "http://amazon.com/" 12 | }, { 13 | "date_added": "13218554442843596", 14 | "guid": "3d87584d-a71f-4ff0-aa18-0c79efcc29c7", 15 | "id": "6", 16 | "name": "CNN", 17 | "type": "url", 18 | "url": "http://cnn.com" 19 | }, { 20 | "date_added": "13218554452536920", 21 | "guid": "179fa996-6b4b-4d9a-beb7-de96fa0d848a", 22 | "id": "7", 23 | "name": "Adobe", 24 | "type": "url", 25 | "url": "http://adobe.com" 26 | }, { 27 | "date_added": "13218554465874578", 28 | "guid": "c03a072c-9956-4429-9737-cc770ecd34c5", 29 | "id": "8", 30 | "name": "Office 365 Portal", 31 | "type": "url", 32 | "url": "http://portal.office.com/" 33 | }, { 34 | "date_added": "13218554481458818", 35 | "guid": "a567e83d-8560-4de0-a03d-53c0dbb90cb4", 36 | "id": "9", 37 | "name": "My Apps", 38 | "type": "url", 39 | "url": "http://myapps.microsoft.com/" 40 | } ], 41 | "date_added": "13218553204407005", 42 | "date_modified": "13218554481458818", 43 | "guid": "00000000-0000-4000-A000-000000000002", 44 | "id": "1", 45 | "name": "Bookmarks bar", 46 | "type": "folder" 47 | }, 48 | "other": { 49 | "children": [ ], 50 | "date_added": "13218553204407488", 51 | "date_modified": "0", 52 | "guid": "00000000-0000-4000-A000-000000000003", 53 | "id": "2", 54 | "name": "Other bookmarks", 55 | "type": "folder" 56 | }, 57 | "synced": { 58 | "children": [ ], 59 | "date_added": "13218553204407497", 60 | "date_modified": "0", 61 | "guid": "00000000-0000-4000-A000-000000000004", 62 | "id": "3", 63 | "name": "Mobile bookmarks", 64 | "type": "folder" 65 | } 66 | }, 67 | "version": 1 68 | }' 69 | 70 | $users = Get-ChildItem "C:\Users" -Exclude Public 71 | $users | ForEach-Object { 72 | New-Item -ItemType Directory -Path "C:\Users\$($_.Name)\AppData\Local\Google\chrome\User Data\default" -force} 73 | 74 | $users | ForEach-Object { 75 | Add-Content -path "C:\Users\$($_.Name)\AppData\Local\Google\chrome\User Data\default\bookmarks" $jsonRepresentation } 76 | -------------------------------------------------------------------------------- /map-printers-scheduledtask.ps1: -------------------------------------------------------------------------------- 1 | #Tests Connection to Print Server 2 | $tpscript= '$fp01 = Test-Connection -ComputerName printserver.domain.com -ErrorAction SilentlyContinue 3 | 4 | #Checks if driver is installed. Installed via win32 intune app using pnputil.exe 5 | $toshiba= test-path C:\Windows\System32\DriverStore\FileRepository\esf6u.inf_amd64_10e58d367838d6a3 6 | 7 | if ($toshiba -eq $true -and $fp01 -eq $true) 8 | {add-printer -ConnectionName "\\printserver.domain.com\Printer Share Name 1" 9 | add-printer -ConnectionName "\\printserver.domain.com\Printer Share Name 2" 10 | add-printer -ConnectionName "\\printserver.domain.com\Printer Share Name 3" }' 11 | 12 | #create mapping script 13 | new-item c:\automation -ItemType directory -force 14 | set-content c:\automation\addprinters.ps1 $tpscript 15 | 16 | if( -Not (Get-ScheduledTask -TaskName "Map Printers" -ErrorAction SilentlyContinue -OutVariable task) ) 17 | { 18 | $Params = @{ 19 | Action = (New-ScheduledTaskAction -Execute 'powershell' -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass c:\automation\addprinters.ps1') 20 | Trigger = (New-ScheduledTaskTrigger -AtLogOn) 21 | Principal = (New-ScheduledTaskPrincipal -UserId (Get-CimInstance –ClassName Win32_ComputerSystem | Select-Object -expand UserName)) 22 | TaskName = 'Map Printers' 23 | Description = 'Map Printers' 24 | } 25 | Register-ScheduledTask @Params 26 | Start-ScheduledTask -TaskName "Map Printers" 27 | } 28 | else 29 | { 30 | Start-ScheduledTask -TaskName "Map Printers" 31 | } 32 | 33 | -------------------------------------------------------------------------------- /powersettings.ps1: -------------------------------------------------------------------------------- 1 | #simple script to set powersettings for the current user. Run in the users context and adjust values as desired 2 | #As of 11/23/19 OMA-URI power policy CSP settings do no appear to work with intune. 3 | 4 | powercfg.exe -x -monitor-timeout-ac 15 5 | powercfg.exe -x -monitor-timeout-dc 10 6 | powercfg.exe -x -standby-timeout-dc 30 7 | powercfg.exe -x -standby-timeout-ac 0 8 | powercfg.exe -x -disk-timeout-ac 0 9 | powercfg.exe -x -disk-timeout-dc 0 10 | -------------------------------------------------------------------------------- /remove-localadmins.ps1: -------------------------------------------------------------------------------- 1 | #simple script to remove any local admins not approved. Just change the names you are filtering by. Can be combined with a 2 | #scheduled task to run more than once 3 | 4 | $admins = Get-LocalGroupMember administrators | where {$_.name -notmatch "dave" -and $_.name -notmatch "domain admins"} | select -ExpandProperty name 5 | $admins | foreach {Remove-LocalGroupMember -group "administrators" -member $_} 6 | -------------------------------------------------------------------------------- /set_startmenu_taskbar_layout.ps1: -------------------------------------------------------------------------------- 1 | #this script will create the layoutmodification.xml file and force a refresh of startmenu/taskbar. Modify the xml to your liking 2 | #currently pins office apps, chrome, company portal 3 | 4 | $layout = ' 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 | Set-content $env:LOCALAPPDATA\Microsoft\Windows\Shell\LayoutModification.xml $layout -Force 38 | Remove-Item 'HKCU:\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\Cache\DefaultAccount\*$start.tilegrid$windows.data.curatedtilecollection.tilecollection' -Force -Recurse 39 | Get-Process Explorer | Stop-Process 40 | -------------------------------------------------------------------------------- /sharepoint_trustedsites.ps1: -------------------------------------------------------------------------------- 1 | New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\sharepoint.com\TENANTNAME-myfiles" -force | New-ItemProperty -name Https -Value 2 2 | New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\sharepoint.com\TENANTNAME-files" -force | New-ItemProperty -name Https -Value 2 -------------------------------------------------------------------------------- /startmenu_layout_plus_scheduledtask.ps1: -------------------------------------------------------------------------------- 1 | #This section creates our layoutmodification xml 2 | 3 | $layout = ' 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 | $UserSID = (New-Object -ComObject Microsoft.DiskQuota).TranslateLogonNameToSID((Get-WmiObject -Class Win32_ComputerSystem).Username) 36 | $Path = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Profilelist\$UserSID" 37 | $UserPath = Get-ItemProperty "Registry::$path" -name "ProfileImagePath" | select -ExpandProperty ProfileImagePath 38 | 39 | Set-content $userpath\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml $layout -Force 40 | 41 | #This Section Creates the powershell script that will be used by our scheduled task and save to c:\automation 42 | 43 | $content = 'New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS 44 | $UserSID = (New-Object -ComObject Microsoft.DiskQuota).TranslateLogonNameToSID((Get-WmiObject -Class Win32_ComputerSystem).Username) 45 | $Path = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Profilelist\$UserSID" 46 | $UserPath = Get-ItemProperty "Registry::$path" -name "ProfileImagePath" | select -ExpandProperty ProfileImagePath 47 | $time = Get-Date -Format "dddd MM/dd/yyyy HH:mm K" 48 | 49 | #This Modifies the time stamp of the layoutmodification xml 50 | 51 | Get-Item $userpath\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml | % {$_.CreationTime = $time} 52 | Get-Item $userpath\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml | % {$_.LastWriteTime = $time} 53 | 54 | # Remove-Item HKU:\$UserSID\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\Cache\DefaultAccount\*$start.tilegrid$windows.data.curatedtilecollection.tilecollection -Force -Recurse 55 | Remove-Item HKU:\$UserSID\Software\Microsoft\Windows\CurrentVersion\CloudStore\Store -Force -recurse 56 | Get-Process Explorer | Stop-Process -force 57 | 58 | sleep 5 59 | 60 | $explorer = get-process explorer 61 | 62 | if ($explorer -eq $false) 63 | { 64 | start-process explorer 65 | } 66 | remove-psdrive -Name HKU' 67 | 68 | new-item c:\automation -ItemType directory -force 69 | set-content c:\automation\startlayout.ps1 $content 70 | 71 | #This Section Creates the Scheduled task to run our startlayout script 72 | 73 | if( -Not (Get-ScheduledTask -TaskName "Start Menu Layout" -ErrorAction SilentlyContinue -OutVariable task) ) 74 | { 75 | $Params = @{ 76 | Action = (New-ScheduledTaskAction -Execute 'powershell' -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass C:\Automation\startlayout.ps1') 77 | Trigger = (New-ScheduledTaskTrigger -once -At ([DateTime]::Now.AddMinutes(1)) -RepetitionInterval (New-TimeSpan -Minutes 15) -RepetitionDuration (New-TimeSpan -Hours 3)) 78 | Principal = (New-ScheduledTaskPrincipal -GroupId "System") 79 | TaskName = 'Start Menu Layout' 80 | Description = 'Start Menu Layout' 81 | } 82 | Register-ScheduledTask @Params 83 | Start-ScheduledTask -TaskName "Start Menu Layout" 84 | } 85 | else 86 | { 87 | Start-ScheduledTask -TaskName "Start Menu Layout" 88 | } 89 | -------------------------------------------------------------------------------- /teams_firewallrules.ps1: -------------------------------------------------------------------------------- 1 | $UserSID = (New-Object -ComObject Microsoft.DiskQuota).TranslateLogonNameToSID((Get-CIMInstance -Class Win32_ComputerSystem).Username) 2 | $ProfilePath = Get-Itemproperty registry::"HKU\$UserSID\Volatile Environment" | select-object -ExpandProperty "USERPROFILE" 3 | New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS 4 | 5 | 6 | $TeamsDir = $profilepath + '\appdata\local\Microsoft\Teams\current\teams.exe' 7 | $firewallRuleName = 'teams.exe' 8 | 9 | $ruleExist = Get-NetFirewallRule -DisplayName $firewallRuleName -ErrorAction SilentlyContinue 10 | 11 | if($ruleExist) 12 | { 13 | Set-NetFirewallRule -DisplayName $firewallRuleName -Profile Any -Action Allow 14 | } 15 | else 16 | { 17 | New-NetfirewallRule -DisplayName $firewallRuleName -Direction Inbound -Protocol TCP -Profile Any -Program $TeamsDir -Action Allow 18 | New-NetfirewallRule -DisplayName $firewallRuleName -Direction Inbound -Protocol UDP -Profile Any -Program $TeamsDir -Action Allow 19 | } --------------------------------------------------------------------------------