I have a PowerShell script which look like this:
# Define time for report (default is 1 day)
$startDate = (get-date).AddDays(-10)
# Store successful logon events from security logs with the specified dates and workstation/IP in an array
# foreach ($DC in $DCs){
# $slogonevents = Get-Eventlog -LogName Security -ComputerName $DC.Hostname -after $startDate | where {$_.eventID -eq 4624 }
# }
$slogonevents = Get-Eventlog -LogName Security -after $startDate | where {$_.eventID -eq 4624 }
# Crawl through events; print all logon history with type, date/time, status, account name, computer and IP address if user logged on remotely
$(foreach ($e in $slogonevents){
# Logon Successful Events
# Local (Logon Type 2)
if (($e.EventID -eq 4624 ) -and ($e.ReplacementStrings[8] -eq 2)){
write-host "Type: Local Logon`tDate: "$e.TimeGenerated "`tStatus: Success`tUser: "$e.ReplacementStrings[5] "`tWorkstation: "$e.ReplacementStrings[11]
}
# Remote (Logon Type 10)
if (($e.EventID -eq 4624 ) -and ($e.ReplacementStrings[8] -eq 10)){
write-host "Type: Remote Logon`tDate: "$e.TimeGenerated "`tStatus: Success`tUser: "$e.ReplacementStrings[5] "`tWorkstation: "$e.ReplacementStrings[11] "`tIP Address: "$e.ReplacementStrings[18]
}
}) *>&1 > D:\Cyber_security\Python\test.txt
I want to run this script from python. this script is saved in my D drive.My python script is:
import subprocess, sys
p = subprocess.Popen(["powershell.exe",
"D:\Cyber_security\Python\login.ps1"],
stdout=sys.stdout)
p.communicate()
but it doesn't work. I need to run powershell as administrator but I don't know how to do it.
CodePudding user response:
You need to nest powershell.exe
calls:
An outer call that calls PowerShell's
Start-Process
cmdlet with-Verb RunAs
, which allows running any executable with elevation.Since what you want to run with elevation is a
.ps1
script, it must be called viapowershell.exe
, the Windows PowerShell CLI, as in your own attempt, except that you explicitly need to incorporate aSet-Location
call to ensure that the script runs in the same working dir. as the caller (C:\Windows\System32
is the default in Windows PowerShell whenStart-Process -Verb RunAs
is used).- If you don't need this, or if you're using
pwsh.exe
, the CLI of the cross-platform PowerShell (Core) 7 edition (which now retains the working dir. by default), the inner call can be simplified to: powershell.exe -Args '-noprofile -file D:\Cyber_security\Python\login.ps1'
- If you don't need this, or if you're using
# See bottom section if you also want to get the exit code of
# the elevated process.
p = subprocess.Popen(
[
"powershell.exe",
"-noprofile", "-c",
r"""
Start-Process -Verb RunAs -Wait powershell.exe -Args "
-noprofile -c Set-Location \`"$PWD\`"; & D:\Cyber_security\Python\login.ps1
"
"""
],
stdout=sys.stdout
)
p.communicate()
Note:
Running a process with elevation:
- involves an interactive UAC confirmation / credentials prompt that cannot be bypassed (unless UAC is turned off, which would be ill-advised)
- invariably runs in a new window.
- prevents direct capture of the elevated process' output streams; you'll have to redirect to (temporary) files instead, which you can do with
Start-Process
'-RedirectStandardOutput
/-RedirectStandardError
parameters.
CLI parameters
-noprofile
and-c
were added:-noprofile
suppresses loading of PowerShell's profiles, and-c
(-Command
) explicitly indicates that what follows are PowerShell commands to execute.-Wait
was added to theStart-Process
call above so as to make the outerpowershell.exe
call wait for the elevated process to exit before continuing.You don't strictly need
powershell.exe
Start-Process -Verb RunAs
for launching an elevated process, but it is the most convenient option.- A Python-based solution is possible, but involves fairly complex use of the WinAPI - see this blog post
- Note that while you can technically use
runas.exe /user:Administrator
utility to create an elevated session, doing so (a) only works with precisely that account, i.e. the built-in account namedAdminstrator
, and that account is often disabled in practice (it is disabled by default).
An alternative approach would be to modify the
.ps1
file to self-elevate on demand (or use a helper.ps1
file that does that) - see this answer
Variation that also gets the exit code of the elevated process:
If your .ps1
script uses the exit
statement in order to deliberately report a (process) exit code that signals success vs. failure and you want to query that exit code, a bit more work is needed:
Start-Process
-PassThru
switch outputs a process-information object representing the newly launched process, whose.ExitCode
property reports the process exit code (after termination).Due to how the
-c
/-Command
CLI parameter works, the innerpowershell.exe
call must useexit $LASTEXITCODE
explicitly to relay the script's exit code as the elevated process' exit code.
p = subprocess.Popen(
[
"powershell.exe",
"-noprofile", "-c",
r"""
exit (
Start-Process -Verb RunAs -PassThru -Wait powershell.exe -Args "
-noprofile -c Set-Location \`"$PWD\`"; & C:\Users\jdoe\Desktop\pg\pg.ps1; exit `$LASTEXITCODE
"
).ExitCode
"""
],
stdout=sys.stdout
)
p.communicate()
print('Terminated with exit code ' str(p.returncode))