以登录用户身份运行命令(远程)

时间:2019-07-31 13:17:31

标签: powershell vbscript scheduled-tasks invoke-command silent

我想分享一下我为自己制作的这项快速功能,可以随时调整并根据您的需求进行改进。

有时您想以远程计算机的登录用户身份运行命令。

您知道,某些命令会为运行它的用户显示输出,如果您使用Invoke-Command运行相同的命令,它将不会返回用户的信息,而是您的信息。 Get-Printer是众多示例中的一个。

没有像PsExec或其他任何第三方应用程序作为本地登录用户来运行命令的简便,快捷的方法,因此我使用VBS,PS1和Scheduled Task实现了此快速功能。

它对用户完全无提示地运行(这要感谢VBS),并且输出显示在控制台中。请注意,它假定远程计算机具有C:\ TEMP。

在Windows 10,powershell v 5.1.17763.503环境中创建。

我不认为这是最终的和完美的,这是我发现需要做的最简单的方法,我只想与大家分享,因为它可能非常有用!

检查注释以获取有关代码的解释,并随时根据需要使用它。请分享您的版本,因为我很好奇看到人们对其进行了改进。一个好主意是使其支持多台计算机,但是正如我所说的,这是一项快速功能,我没有太多时间来完善它。

话虽这么说,但我多次使用它没有问题:)

**返回的输出为字符串形式,如果要具有适当的对象,请添加'| ConvertFrom-String'并使用它:)

请注意:抓住当前登录用户名的方式是通过QWINSTA(因为Win32_ComputerSystem-用户名仅在用户本地登录时才可靠,如果用户使用RDP则不正确) /远程桌面)。因此,这就是我用来获取用户名的方式,但是请注意,在我们的法语环境中,QWINSTA中的用户名属性的名称为“ UTILISATEUR”,因此您必须将其更改为您的需求(英语或其他语言)去工作。如果我没记错的话,它是英文的“ USERNAME”。

在这一行:

$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR

请参阅下面答案中的代码。

1 个答案:

答案 0 :(得分:0)

function RunAsUser {

Param ($ComputerName,$Scriptblock)

#Check that computer is reachable
Write-host "Checking that $ComputerName is online..."

if (!(Test-Connection $ComputerName -Count 1 -Quiet)) {
Write-Host "$ComputerName is offline" -ForegroundColor Red
break
}

#Check that PsRemoting works (test Invoke-Command and if it doesn't work, do 'Enable-PsRemoting' via WMI method).
#*You might have the adjust this one to suit your environement.
#Where I work, WMI is always working, so when PsRemoting isn't, I enable it via WMI first.
Write-host "Checking that PsRemoting is enabled on $ComputerName"
if (!(invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)) {
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "powershell.exe -command Enable-PSRemoting -SkipNetworkProfileCheck -Force" | Out-Null

    do {
    Start-Sleep -Milliseconds 200
    } until (invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)
}


#Check that a user is logged on the computer
Write-host "Checking that a user is logged on to $ComputerName..."
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
if (!($LoggedOnUser) ) {
Write-Host "No user is logged on to $ComputerName" -ForegroundColor Red
break
}


#Creates a VBS file that will run the scriptblock completly silently (prevents the user from seeing a flashing powershell window)
@"
Dim wshell, PowerShellResult
set wshell = CreateObject("WScript.Shell")
Const WindowStyle = 0
Const WaitOnReturn = True
For Each strArg In WScript.Arguments
arg = arg & " " & strArg
Next 'strArg
PowerShellResult = wshell.run ("PowerShell " & arg & "; exit $LASTEXITCODE", WindowStyle, WaitOnReturn)
WScript.Quit(PowerShellResult)
"@ | out-file "\\$ComputerName\C$\TEMP\RAU.vbs" -Encoding ascii -force

#Creates a script file from the specified '-Scriptblock' parameter which will be ran as the logged on user by the scheduled task created below.
#Adds 'Start-Transcript and Stop-Transcript' for logging the output.
$Scriptblock = "Start-Transcript C:\TEMP\RAU.log -force" + $Scriptblock + "Stop-Transcript"
$Scriptblock | out-file "\\$ComputerName\C$\TEMP\RAU.ps1" -Encoding utf8  -force

#On the remote computer, create a scheduled task that runs the .ps1 script silently in the user's context (with the help of the vbs)
Write-host "Running task on $ComputerName..."
Invoke-Command -ComputerName $ComputerName -ArgumentList $LoggedOnUser -ScriptBlock {
    param($loggedOnUser)

    $SchTaskParameters = @{
    TaskName = "RAU"
    Description = "-"
    Action = (New-ScheduledTaskAction -Execute "wscript.exe" -Argument "C:\temp\RAU.vbs C:\temp\RAU.ps1")
    Settings = (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd)
    RunLevel = "Highest"
    User = $LoggedOnUser
    Force = $true
    }

    #Register and Start the task
    Register-ScheduledTask @SchTaskParameters | Out-Null
    Start-ScheduledTask -TaskName "RAU"

    #Wait until the task finishes before continuing
    do {
    Write-host "Waiting for task to finish..."
    $ScheduledTaskState = Get-ScheduledTask -TaskName "RAU" | Select-Object -ExpandProperty state
    start-sleep 1
    } until ( $ScheduledTaskState -eq "Ready" )

    #Delete the task
    Unregister-ScheduledTask -TaskName "RAU" -Confirm:$false
}
Write-host "Task completed on $ComputerName"      
#Grab the output of the script from the transcript and remove the header (first 19) and footer (last 5)
$RawOutput = Get-Content "\\$ComputerName\C$\temp\RAU.log" | Select-Object -Skip 19
$FinalOutput = $RawOutput[0..($RawOutput.length-5)]

#Shows output
return $FinalOutput


#Delete the output file and script files
Remove-Item "\\$ComputerName\C$\temp\RAU.log" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.vbs" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.ps1" -force

}

#____________________________________________________

#Example command
#Note: Sometimes Start-Transcript doesn't show the output for a certain command, so if you run into empty output, add: ' | out-host' or '| out-default' at the end of the command not showing output.
$Results = RunAsUser -ComputerName COMP123 -Scriptblock {
get-printer | Select-Object name,drivername,portname | Out-host
}


$Results

#If needed, you can turn the output (which is a string for the moment) to a proper powershell object with ' | ConvertFrom-String' 
相关问题