在普通用户桌面下使用特定用户权限来运行程序
开始使用一段时间PowerShell之后,应该会发现有不少东西是要管理员权限才能运行,但是公司内大部分人的权限不是管理员才是常态。
在Windows桌面使用中有个小技巧,就是按着Shift再去对程序右键,右键菜单会多出一个以其他用户身份运行,在弹出的对话框里面输入管理员账号,这个程序就会运行在管理员权限下了。
但正常情况下,对着PowerShell的.ps1脚本这样Shift+右键
是没有这个选项给你的,虽然你可以先Shift+右键
来以管理员运行 PowerShell.exe
和PowerShell_ISE.exe
,再去打开.ps1脚本文件来让.ps1脚本以管理员权限运行,本来Shift+右键
就有点麻烦了,这样套娃来运行就更麻烦了。
CMD脚本的.bat文件倒是可以用Shift+右键来操作,所以有不少简单的脚本我还是会习惯直接拿.bat来写。
PowerShell中的 -Credential “凭据”
在PowerShell的学习使用中会时不时看到有些命令有这样一个参数"-Credential"
——“凭据”,这个就是用来让命令以指定用户来运行的参数。
例如:
以指定用户凭据来运行命令
1# 弹窗让你输入账号密码获取对应账号的权限
2$AdminUserCredential = Get-Credential
3
4# 这就是 PowerShell版本的 RUNAS /user:Administrator
5Start-Process -FilePath regedit.exe -Credential $AdminUserCredential
这样你就能以你刚刚输入的账号权限来运行 regedit.exe
注册表编辑器了
但是不是所有命令都支持加 "-Credential"
参数的,我希望整个脚本都以管理员运行,有什么方法吗?
检查脚本是否为管理员权限运行,不是就重新以指定用户凭据运行脚本
1# 检测是否为管理员权限的函数
2function Check-IsElevated {
3 $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
4 $p = New-Object System.Security.Principal.WindowsPrincipal($id)
5 if ($p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
6 return $true
7 }
8 else {
9 return $false
10 }
11}
12
13# 不是管理员权限就 Get-Credential 获取账户凭据后再以账户权限运行,$PSCommandPath 是特殊变量,代表脚本文件的路径。
14if ( -Not $(Check-IsElevated) ) {
15 Write-Host "当前账户非管理员权限"
16 $AdminUserCredential = Get-Credential
17 Start-Process -FilePath "powershell.exe" -ArgumentList "$PSCommandPath" -Credential $AdminUserCredential # -WindowStyle Hidden
18 exit
19}
20
21# ------!!!------ 下面的内容就全都是管理员运行的了 ------!!!------
22
23# 启动 PowerShell ISE
24Start-Process -FilePath "powershell_ise.exe"
25
26# 在C:\Windows\ 下面创建一个 001AdminTest 文件夹
27New-Item -Path "C:\Windows\001AdminTest" -ItemType Directory
要是我连账号密码都不想输入,想直接丢给普通用户用,有什么方法吗?
用户凭据账号密码直接写在脚本中
不要把管理员凭据明文写入到脚本中给普通用户使用,这是个极高风险的操作。
1# 管理员凭据
2$AdminUserName = "$env:COMPUTERNAME\Administrator" # 拥有管理员权限的账号,这里写的是本地管理员
3$AdminUserPassword = "AdminPassword" # 拥有管理员权限的账号的密码
4$SecureAdminUserPassword = ConvertTo-SecureString $AdminUserPassword -AsPlainText -Force
5$AdminUserCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminUserName, $SecureAdminUserPassword
6
7# 不需要手动输入就可以给 -Credential 参数提供管理员凭据
8Start-Process -FilePath "powershell_ise.exe" -Credential $AdminUserCredential
直接明文也太危险了,有没有更安全一点方法?
用户凭据的密码在本机加密后再取用
首先先把密码给转成安全字符,然后再加密,加密后的密码只有这台计算机才能还原。
1# 输入密码转成安全字符串
2$SecureString = Read-Host "请输入密码" -AsSecureString
3# 不想弹窗输入也可以用 $SecureString = ConvertTo-SecureString -String "PassowrdText" -AsPlainText -Force 但是不建议
4
5# 安全字符串转换为加密的标准字符串
6$EncryptedStandardString = ConvertFrom-SecureString $SecureString
7
8# 加密的标准字符串导出文本文件
9$EncryptedStandardString | Out-File -FilePath "D:\EncryptedPassord.txt"
然后到用的时候
1# 密码文件路径
2$EncryptedPassordPath = "D:\EncryptedPassord.txt"
3
4# 管理员凭据
5$AdminUserName = "$env:COMPUTERNAME\Administrator"
6$SecureAdminUserPassword = Get-Content -Path $EncryptedPassordPath | ConvertTo-SecureString
7$AdminUserCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminUserName, $SecureAdminUserPassword
8
9# 不需要手动输入密码就可以给 -Credential 参数提供管理员凭据
10Start-Process -FilePath "powershell_ise.exe" -Credential $AdminUserCredential
由于
ConvertTo-SecureString
接受的就是字符串,可以不从文件文件获取,直接写在脚本里也行,例如:
$SecureAdminUserPassword = ConvertTo-SecureString -String "01000000d08c9ddf0115d111……e98c0ab0f1a9f2e251611f9"
但是不推荐这样,你把密码文件分离开来的话,放在共享文件服务器还是什么别的地方,还能用访问权限来保护一下。 反正就是一串字符,能存字符就行,拆开放也行,再加密也行,可以发散一下思路来增加授权限制来间接保护一下,写死在脚本直接一锅端。
安全是安全了,就算加密文件丢了,不在对应的电脑上解密也用不了,但是我又不想每台电脑都生成一次,能不能通用一点?
用户凭据的密码以密钥加密后再取用
1# 生成一个随机的Key,随便把导出成文件
2$key = New-Object Byte[] 32
3[System.Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key)
4$key | Out-file "D:\AES.key"
5
6# 输入密码转成安全字符串
7$SecureString = Read-Host "输入密码" -AsSecureString
8# 不想弹窗输入也可以用 $SecureString = ConvertTo-SecureString -String "PassowrdText" -AsPlainText -Force 但是不建议
9
10# 安全字符串转换为加密的标准字符串,以Key来加密
11$EncryptedStandardString = ConvertFrom-SecureString $SecureString -key $key
12
13# 加密的标准字符串导出文本文件
14$EncryptedStandardString | Out-File -FilePath "D:\EncryptedPassord.txt"
-key
参数本质上也是字符串数组,也可以直接写进脚本里面,但也是不推荐这样的。
$Key = (3,4,2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43)
$StandardString = ConvertFrom-SecureString $SecureString -Key $Key
ConvertFrom-SecureString
也可以不用-key
参数,用-SecureKey
,但按文件分开存放的增加限制的思路的话,其实区别不大……
然后到用的时候
1# Key文件路径
2$KeyPath = "D:\AES.key"
3# 密码文件路径
4$EncryptedPassordPath = "D:\EncryptedPassord.txt"
5
6# 管理员权限
7$AdminUserName = "$env:COMPUTERNAME\Administrator"
8
9$key = Get-Content -Path $KeyPath
10$EncryptedPassord = Get-Content -Path $EncryptedPassordPath
11$SecureAdminUserPassword = ConvertTo-SecureString -String $EncryptedPassord -Key $key
12$AdminUserCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminUserName, $SecureAdminUserPassword
13
14# 不需要手动输入密码就可以给 -Credential 参数提供管理员权限
15Start-Process -FilePath "powershell_ise.exe" -Credential $AdminUserCredential
把脚本打包成exe
除了上面这几中加密分开存放的方面外,还有一个方法可以增加一定的安全性,把脚本打包成exe。
之前我在 PowerShell 入门教程推荐和常用代码片段 - tjxwork (tjxblog.com) 里面有提到一个PowerShell开发工具
SAPIEN PowerShell Studio 强大的PowerShell GUI设计器和脚本调试器 (sapien.com)
这个软件可以把PowerShell脚本打包成exe,也可以嵌入凭据,打包出来的exe可以按嵌入的凭据来直接运行,他们说嵌入的凭据是加密的。
但有没有脚本内容有没有额外的加密我就没留意了,但总的来说光打包成exe这个就能拦住大部分人了,组合起来使用能相对更安全一点。
参考
淺談 PowerShell 中的密碼字串加密處理-黑暗執行緒 (darkthread.net)
PowerShell 脚本中的密码 - sparkdev - 博客园 (cnblogs.com)
ConvertFrom-SecureString (Microsoft.PowerShell.Security) - PowerShell | Microsoft Learn
ConvertTo-SecureString (Microsoft.PowerShell.Security) - PowerShell | Microsoft Learn
补充
不管怎么说,把通用的管理员凭据,写入一个或者多个文本文件里面,在普通用户下运行来自动使用。
这种行为总是不太安全的,各种方法混合验证来使用会相对的更安全一点。
毕竟SecureString Class
安全字符串 这个东西本来就不是非常安全的选择。
平台兼容/DE0001:不应使用安全字符串 (github.com)
原文作者:tjxwork
原文链接:https://www.tjxblog.com/blog/2023-0005
发布时间:2023-02-15
评论