P/Invoke SHSetKnownFolderPath 失败

P/Invoke SHSetKnownFolderPath Failing

我认为这将是一个足够简单的脚本。我在这里看到这篇关于如何使用 powershell 将文件夹重定向到 OneDrive 的文章:https://stealthpuppy.com/onedrive-intune-folder-redirection/

我意识到这个脚本对我不起作用,因为它的编写方式需要用户上下文并且不能 运行 使用 Task Scheduler 静默地使用,所以我开始尝试“重写”脚本使用系统上下文。除了我似乎无法理解的一大块之外,一切似乎都在工作。我认为它是 C#,我只熟悉 powershell。我只关心重定向下载文件夹,所以他就是我的。

#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

除了我在第 74 行收到一条错误消息外,一切似乎都正常, “重定向 {374DE290-123F-4565-9164-39C4925E467B} 时出错。Return 代码 -2147024894 = 系统找不到指定的文件

我几乎花了一整天的时间来解决这个问题,但一无所获。如有任何帮助,我们将不胜感激!

你有两个问题:

  • 眼前的技术问题:The system cannot find the file specified 表示无法识别指定的 KNOWNFOLDERID GUID。

    • 就是说,在您的两个 GUID 中,它是 {7d83ee9b-2244-4e70-b1f5-5393042af1e4},而不是您的错误消息中提到的 {374DE290-123F-4565-9164-39C4925E467B}(下载文件夹),这是未知的。
  • 概念性问题:您正在尝试为 特定用户 调用 SHSetKnownFolderPath,这需要您传递所谓的访问令牌将感兴趣的用户表示为 hToken 参数。

    • 由于您将 0 传递给 hToken,因此您总是在为 当前 用户更新。

如果您想避免通过 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 获取代表其他用户的访问令牌的额外复杂性,并且可能在将来的某个时候停止工作。