【问题标题】:New-PSDrive's "-Persist" flag not working: drives removed on rebootNew-PSDrive“-Persist”标志不起作用:重新启动时删除的驱动器
【发布时间】:2021-02-09 18:46:15
【问题描述】:

脚本正确挂载驱动,但重启机器后驱动没有持久化:

function RemapDrive {
    param(      
        $DriveLetter,
        $FullPath,
        $Credential     
    )
    
    Write-Host "Trying to remove $DriveLetter in case it already exists ..."    
    # $DriveLetter must be concatenated with ":" for the command to work
    net use "${DriveLetter}:" /del
    
    ## $DriveLetter cannot contain ":"
    $psDrive = New-PSDrive -Name "$DriveLetter" -PSProvider "FileSystem" -Root "$FullPath" -Credential $Credential -Scope "Global" -Persist
    
    Write-Host "$DriveLetter was successfully added !"  
}

function BuildCredential {
    param (
        $Username,
        $Password
    )
    $pass = ConvertTo-SecureString $Password -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential ($Username, $pass)
    return $credential
}

$credential = (BuildCredential -Username "xxxxxx" -Password "yyyyyy")[-1]

RemapDrive -DriveLetter "X" -FullPath "\\my-server\x" -Credential $credential

我发现了什么:

“当您在本地范围内(即没有点源)时,Persist 参数不会将 PSDrive 的创建持续到您运行命令的范围之外。如果您在脚本中运行 New-PSDrive,并且希望新驱动器无限期地持续存在,则必须对脚本进行点源。为获得最佳结果,要强制新驱动器持续存在,除了将 Persist 添加到命令中之外,还要将 Global 指定为 Scope 参数的值。”

我尝试使用“. .\my-script.ps1”执行脚本(对脚本进行点源?),但结果是一样的。

玩弄“网络使用”和注册表以尝试添加网络驱动器也让我陷入了死胡同。


规格:

Windows 10 家庭版

Powershell 版本:

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      18362  1171

【问题讨论】:

  • @TheGameiswar "您需要从以登录 Windows 的同一用户身份运行的 PowerShell 会话映射驱动器" $env:UserName in情况下我遗漏了一些明显的东西)。但是您的链接可能会帮助其他找到我的问题的人。
  • 我们在工作中遇到了同样的问题,但我们解决了;我只是不记得如何,但是,我会搜索我们的脚本,让它工作。认为这就像在-Persist 之后提供“是”一样简单。

标签: powershell


【解决方案1】:

基本上,New-PSDrive 没有来自net use/SAVECRED 参数,并且不会作为运行脚本的用户以外的用户持续映射驱动器。

有三种方法可以处理:

  1. [推荐] 修复文件共享权限,而不是使用单独的用户名/密码,然后使用不带凭据标志的 New-PSDrive -Name "$DriveLetter" -PSProvider "FileSystem" -Root "$FullPath" -Scope 'Global' -Persist。这假设您的文件共享允许 kerberos 登录,因此在某些边缘情况下可能无法正常工作。
  2. 使用net use,包括用户名、密码、/persistent:yes/savecred。这可以在 powershell 中完成,没有任何问题。
  3. 设置您必须在启动时运行的 powershell 脚本。
  4. 设置您的脚本以使用凭证管理器 - 请参阅答案here
  • 安装 CredentialManager powershell 模块
  • 设置HKCU\Network\[drive letter]\ConnectionType = 1
  • 设置HKCU\Network\[drive letter]\DeferFlags= 4

【讨论】:

  • 非常感谢您的详细回答。关于#1,由于我无法控制的原因,我们被困在使用单个 smb 用户。 #2 不是微不足道的(使用脚本):用户名 + 密码 + /persistent:yes + /savecred 抛出“冲突开关”错误。 solution 似乎正在使用 cmdkeynet use 结合使用,但这也不是微不足道的(尽管会重试)。 #3 当然是一个选项,但我不喜欢在每个用户的机器上都有明文密码。我不知道#4,我需要做一些研究。很好的总结,再次感谢!
  • 选项 #2 最终起作用了!有一些额外的步骤,但它有效:我在下面添加了一个完整的答案来显示脚本。非常感谢,我对那些身份验证+注册问题有点迷茫,你的回答有助于澄清那些棘手的事情。
【解决方案2】:

最终起作用的是 user19702 的选项 #2,在用户名和密码的注册方面做了一些额外的工作。

警告:正如他所提到的,最好的选择(选项 #1)应该是“修复文件共享权限,而不是使用单独的用户名/密码”。在我的情况下这是不可能的,这就是为什么我不得不选择选项 #2。

这是脚本:

# ---
# Helper functions:

function RemapDrive {
    param(      
        $DriveLetter,
        $Server,
        $FullPath,
        $Credential     
    )
    

    # For net.exe to work, DriveLetter must end with with ":"

    Write-Host "Trying to remove $DriveLetter in case it already exists ..."        
    net use "$DriveLetter" /del
    
    # "net use" requires username and password as plain text
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($credential.Password)
    $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
    $Username=$Credential.Username
    
    Write-Host "Registring credentials for server '$Server' ..."    
    cmdkey /add:$Server /user:$Username /pass:$Password
    
    Write-Host "Mapping the drive ..."
    net use $DriveLetter $FullPath /persistent:yes i
    
    Write-Host "$DriveLetter was successfully added !"  
}

function BuildCredential {
    param (
        $Username,
        $Password
    )
    $pass = ConvertTo-SecureString $Password -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential ($Username, $pass)
    return $credential
}


# ---
# Process to execute:

$credential = (BuildCredential -Username "xxxxxx" -Password "yyyyyy")[-1]

RemapDrive -DriveLetter "X:" -Server "my-server" -FullPath "\\my-server\x" -Credential $credential

如果您不想在BuildCredential 中使用硬编码密码,但想提示用户:

function GetCredential {
    param(
        $Label
    )
    $credential = Get-Credential -Message "Write your credentials for '$Label':"
    if(!$credential) {
        throw "A credential was needed to continue. Process aborted."
    }       
    return $credential
}

另外,如果您不想使用$Server 作为参数,而是想使用正则表达式从$FullPath 中提取它,您可以这样做。

它假定$FullPath 具有以下格式:\\server-name\dir1\dir2\etc

    # Get server name using regex:
    $FullPath -match '\\\\(.*?)\\.*?'
    $Server = $Matches[1]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-04
    • 1970-01-01
    相关资源
    最近更新 更多