I thought this would be a simple enough script. I came across this article about how to use powershell to redirect folders to OneDrive here: https://stealthpuppy.com/onedrive-intune-folder-redirection/
I realized this script would not work for me, as the way it is written it requires user context and cannot be run silently using Task Scheduler, so I set out to try and "rewrite" the script using a system context. All seems to be working except for one chunk that I can't seem to understand. I think it's C# and I'm only familiar with powershell. I am only concerned with redirecting the downloads folder, so his is what I have.
#These are the potential GUIDs for the Downloads KFM path of the user
$Guids = $null
$Guids = @()
$Guids += [pscustomobject]@{
Guid = '{374DE290-123F-4565-9164-39C4925E467B}'
Paths = @()
}
$Guids += [pscustomobject]@{
Guid = '{7d83ee9b-2244-4e70-b1f5-5393042af1e4}'
Paths = @()
}
#Log Variables
$timestamp = Get-Date -Format o | ForEach-Object { $_ -replace ":", "." }
$LogPath = "$env:USERPROFILE\AppData\Local\Intune-PowerShell-Logs\OneDriveSync-$timestamp.txt"
Start-Transcript -Path $LogPath
$CurrentUsers = Get-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" | Where {($_.ProfileImagePath -notmatch '.NET') -and ($_.ProfileImagePath -notmatch 'Default') -and ($_.ProfileImagePath -match "Users")} | select ProfileImagePath,PSChildName
ForEach ($CurrentUser in $CurrentUsers)
{
$SourcePath = "$($CurrentUser.ProfileImagePath)\Downloads"
$Targetpath = "$($CurrentUser.ProfileImagePath)\OneDrive\Downloads"
$Rootpath = "HKU:\$($CurrentUser.PSChildName)"
$ShellFolderspath = "$RootPath\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
$UserShellFolderspath = "$Rootpath\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
#region 1 - Identify registry keys to update
New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS -ErrorAction SilentlyContinue
#Adding Downloads Guids to array
ForEach ($object in $Guids)
{
#Check Shell Folders Path
If ($Item = Get-ItemProperty $ShellFolderspath -Name $object.Guid -ErrorAction SilentlyContinue)
{
"$($object.guid) found in Shell Folders path"
$Object.paths += @($Item.PSpath)
}
#Check User Shell Folders Path
If ($Item = Get-ItemProperty $UserShellFolderspath -Name $object.Guid -ErrorAction SilentlyContinue)
{
"$($object.guid) found in User Shell Folders path"
$Object.paths += @($Item.PSpath)
}
}
#endregion
#region 2
# Define SHSetKnownFolderPath if it hasn't been defined already
$Type = ([System.Management.Automation.PSTypeName]'KnownFolders').Type
If (-not $Type)
{
$Signature = @'
[DllImport("shell32.dll")]
public extern static int SHSetKnownFolderPath(ref Guid folderId, uint flags, IntPtr token, [MarshalAs(UnmanagedType.LPWStr)] string path);
'@
$Type = Add-Type -MemberDefinition $Signature -Name 'KnownFolders' -Namespace 'SHSetKnownFolderPath' -PassThru
}
#Test if new directory exists
If (!(Test-Path -Path $Targetpath -PathType Container))
{
New-Item -Path $TargetPath -Type Directory -Force
}
#Validate the path
If (Test-Path $TargetPath -PathType Container)
{
#Call SHSetKnownFolderPath
#return $Type::SHSetKnownFolderPath([ref]$KnownFolders[$KnownFolder], 0, 0, $Path)
ForEach ($object in $Guids)
{
$result = $Type::SHSetKnownFolderPath([ref]$object.guid, 0, 0, $Targetpath)
If ($result -ne 0)
{
$errormsg = "Error redirecting $($Object.guid). Return code $($result) = $((New-Object System.ComponentModel.Win32Exception($result)).message)"
Throw $errormsg
}
}
}
Else
{
Throw New-Object System.IO.DirectoryNotFoundException "Could not find part of the path $Path."
}
#endregion
#region 3 - Set new downloads directory
ForEach ($Object in $Guids)
{
ForEach ($path in $object.paths)
{
Set-ItemProperty -Path $path -Name $object.Guid -Value $Targetpath -Verbose
}
}
#endregion
#region 4
#Move files from old directory to the new one
#Robocopy.exe "$SourcePath" "$Targetpath" /E /MOV /XJ /XF *.ini /R:1 /W:1 /NP
#endregion
#}
}
Stop-Transcript
All seems to work except that I get an error on line 74 that says, "Error redirecting {374DE290-123F-4565-9164-39C4925E467B}. Return code -2147024894 = The system cannot find the file specified"
I have spent almost an entire work day trying to tackle this problem and am getting nowhere. Any help would be appreciated!
You have two problems:
The immediate, technical problem: The system cannot find the file specified
implies that the specified KNOWNFOLDERID GUID is not recognized.
{7d83ee9b-2244-4e70-b1f5-5393042af1e4}
, not the one mentioned in your error message, {374DE290-123F-4565-9164-39C4925E467B}
(the Downloads folder), that is unknown.A conceptual problem: You're trying to call SHSetKnownFolderPath
for specific users, which requires that you pass a so-called access token representing the user of interest as the hToken
argument.
0
for hToken
, you're always updating for the current user.If you want to avoid the additional complexity of obtaining access tokens representing other users via the LogonUser
WinAPI function, you can bypass SHSetKnownFolderPath
calls and write directly to the registry, as your code in part already does; however, note that while that should work as of this writing, doing so is discouraged and may at some point in the future stop working.