From time to time it can be useful to execute an action as a "Run once at Startup" script once as a user or system when the computer starts up. Intune does not have a "Run once at Startup" feature. That's why I created two scripts that give me the opportunity to make a change or cleanup before the end user opens a program or runs into an error. I have this for example with the "Clear Microsoft Teams cache once" used.
Because a script doesn't always need to be run with the same permissions, I use two different methods. The first is via Scheduled Task and runs the script as a "system" user. This ensures that tasks with elevated rights or, for example, for all users can be executed at the same time.
The second version uses the "RunOnce registry key" function. This will run the script once as a user. You can easily distribute both scripts with Intune and thus as "Run once at Startup".
Add your code to both scripts after the comment and delete the "Write-Host" part:
Run one at Startup - as User
Windows has one or two simple registry entries that can be used to run a task as a user.
These are the following two:
- HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce
- HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce
The first one in the "Current User" only runs the task for the specific user himself.
In the second, which is in the "Local Machine" context, the task is executed once for each user.
In my script I intercepted both cases.
If you distribute the script in Intune as a PowerShell script (Devices > Windows > PowerShell scripts), you can select "Yes" or "No" in the options for "Run this script using the logged on credentials". With "Yes", the script will only be executed on the assigned user (The script should then be assigned to a user group). With "No" the script is executed as system and the registry entry is set in the "Local Machine" content.
The script is not deleted after execution because it can be used by multiple users.
Run one at Startup - as System
To run the script once when the computer starts up as a system, I use a "Scheduled Task". This task is executed when it starts, executing its defined script, which it then deletes. In addition, the "Scheduled Task" itself is also deleted, so that there are no remains on the computer after execution, apart from the log.
Here, the version as a system must be selected for distribution:
Hey nice article,
I downloaded your script to test it out, (run as system)
when I run it I receive an error about:
Cannot bind argument to parameter 'Path' because it is an empty string.
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
I didn't edit the script, I just downloaded it and run it without editing what so ever.
This is the full error output from Powershell:
$PackageName = "run-once"
$Version = "1"
$Path_4netIntune = "$Env:Programfiles\4net\EndpointManager"
Start-Transcript -Path "$Path_4netIntune\Log\$PackageName.log" -Force
try{
# Check if Task exist with correct version
$task_existing = Get-ScheduledTask -TaskName $PackageName -ErrorAction SilentlyContinue
if($task_existing.Description -like "Version $Version*"){
############################################################################################
# YOUR CODE TO RUN ONCE
Write-Host "GUGUS :)"
# END RUN ONCE CODE
############################################################################################
# Delete ScheduledTask
Unregister-ScheduledTask -TaskName $PackageName -Confirm:$false
# Delete Script
Remove-Item -Path $MyInvocation.MyCommand.Source
}else{
# script path
$script_path = "$Path_4netIntune\Data\$PackageName.ps1"
# get and save file content
Get-Content -Path $($PSCommandPath) | Out-File -FilePath $script_path -Force
# Register scheduled task to run at startup
$schtaskDescription = "Version $Version"
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal= New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType "ServiceAccount" -RunLevel "Highest"
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass -File `"$script_path`""
$settings= New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName $PackageName -Trigger $trigger -Action $action -Principal $principal -Settings $settings -Description $schtaskDescription -Force
}
}catch{
Write-Error $_
}
Stop-Transcript : Cannot bind argument to parameter 'Path' because it is an empty string.
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
Did you paste in the content itself or did you call the script?
If you paste in the content in a Terminal, it won't work, cause of the "$PSCommandPath", which is the script itself.
If you run a terminal as system, just call the script with its pat like
&"C:\...\script.ps1"
Nice article but not why not working for me. I am getting below error
Transcript started, output file is C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\Open-Sway-script.log
C:\Users\UserName\Documents\Run Once\scloud-run-once-at-startup_Registry-OpenWebsite.ps1 : Could not find a part of the path 'C:\Program Files\MEM\Data\Open-Website.ps1'.
At line:1 char:1
+ .\scloud-run-once-at-startup_Registry-OpenWebsite.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,scloud-run-once-at-startup_Registry-OpenWebsite.ps1
Looks like it is looking for the file
'C:\Program Files\MEM\Data\Open-Website.ps1'.
Please help. Thanks in advance!
Looks like the folder doesn't exist in your environment. I added a line to fix that. You can download the latest script on GitHub.
This is brilliant.
Will I be able to Mount a NAS drive using this method?
I just need to run on every reboot though so the NAS is mounted each time as we have found some instances where users drive just vanishes,
they are full Azure and Intuned, but have the NAS as Scans folder.
Yes you could achive that as well.
The only challange or "risk" is to bring the credentials of the NAS to your devices. If you place thiose in the script, they will be sotred in clear text.
But maybe for a Scan2Folder scenario this is no big deal.
If so just place this in the script before the drive connection:
cmdkey /add:$NAS_IPAddress /user:$NAS_user /pass:$NAS_password
Hope that helps 🙂