Python Forum

Full Version: Running powershell command in flask wtf form
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
hi all,

ive made this flask-wtf form

from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, DecimalField, RadioField, SelectField, TextAreaField, FileField, SubmitField
from wtforms.validators import InputRequired, Length, DataRequired, EqualTo, Regexp, ValidationError
import re
import subprocess

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secretkey'


class PasswordForm(FlaskForm):
    un = StringField('Username', [InputRequired(message='please enter your Username')])
    op = PasswordField('Current Password', [InputRequired(message='please enter your current password')])
    np = PasswordField('New Password', [InputRequired(message='please enter your new password')])
    cnp = PasswordField('Confirm New Password')
    dom = SelectField('Domain', choices=[('lon-prod-dc01.domain.com', 'prod'), ('lon-corp-dc01.domain.com', 'corp'), ('dc01.robo84.net', 'robo84')])
    
    def validate_un(form, field):
        if not field.data == form.un.data.lower():
            raise ValidationError('Username needs to be Lowercase')
    
    def validate_np(form, field):
        if form.un.data:
            if any (name in field.data.lower() for name in form.un.data.split(".")):
                raise ValidationError('New password cant contain firstname or lastname')
        if field.data.lower() == form.op.data.lower():
            raise ValidationError('New password cant match Current password')
        if len(field.data) < 12:
            raise ValidationError('New password must be at least 12 characters')
        if not re.search(r"[0-9]", field.data):
            raise ValidationError('New password has to contain one number')
        if not re.search(r"[a-z]", field.data):
            raise ValidationError('New password has to contain one lower case character')
        if not re.search(r"[A-Z]", field.data):
            raise ValidationError('New password has to contain one upper case character')
        if not re.search(r"[\`\¬\!\"\£\$\%\^\&\*\(\)\-\_\=\+\\\|\[\]\;\'\#\,\.\/\{\}\:\@\~\<\>\?]", field.data):
            raise ValidationError('New password has to contain one special character')
        if not field.data == form.cnp.data:
            raise ValidationError('New password has to match Confirm new password')
        
    
@app.route('/password', methods=['GET', 'POST'])
def password():
    form = PasswordForm()
    if request.method == 'POST' and form.validate():
        return '<h1>The username is {}. The old password is {}. the new password is {}. changing for domain {}'.format(form.un.data, form.op.data, form.cnp.data, form.dom.data)
        return subprocess.run('C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe ipconfig', shell=True)
    return render_template('password.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)
basically if all validation pass, when they click the submit button, it will return there values for username/old password/new password and domain

this works but now i want it to also run a PS command as well ie if all validations pass and they click on the submit button

for testing im just going to run an “ipconfig” in PS but im going to change this with the “set-adaccountpassword” with the variables they entered so it changes there password for them

thanks,
rob
tried this but didnt work,

@app.route('/password', methods=['GET', 'POST'])
def password():
    form = PasswordForm()
    if request.method == 'POST' and form.validate():
        return '<h1>The username is {}. The old password is {}. the new password is {}. changing for domain {}'.format(form.un.data, form.op.data, form.cnp.data, form.dom.data)
        subprocess.run('C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe Set-ADAccountPassword -Identity form.un.data -OldPassword (ConvertTo-SecureString -AsPlainText "form.op.data" -Force) -NewPassword (ConvertTo-SecureString -AsPlainText "form.cnp.data" -Force -server form.dom.data)', shell=True)
    return render_template('password.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)
to test it, i log out and back in with the new password that i have set but the login is still using my old password
"form.un.data" is a str, but it is not the str from your form. It is quite literally "form.un.data". Same goes for "form.op.data"
(Jun-25-2024, 08:16 PM)deanhystad Wrote: [ -> ]"form.un.data" is a str, but it is not the str from your form. It is quite literally "form.un.data". Same goes for "form.op.data"

so
form.un.data, form.op.data, form.cnp.data, form.dom.data
there not variables, what are variables then would it be

un, op, np, cnp, dom
under the class section
form.un.data returns a value from your form, but you cannot call this from powershell. Powershell knows nothing about your form and has no way to get form.un.data. Your program needs to get the value returned by form.un.data and pass that value in the subprocess run() call. You could use format to do the replacement (I prefer the new f'string format).
# Making fake form data
from collections import namedtuple
field = namedtuple("Field", ["name", "data"])
class form:
    un = field("un", "my.username")
    op = field("op", "my.old.password")
    np = field("np", "my.new.password")

# This is what you are passing as the command.
cmd_str = 'change password for "form.un.data" from "form.op.data" to "form.np.data"'
print(cmd_str)

# You should pass the form data in the command string.
cmd_str = f'change password for "{form.un.data}" from "{form.op.data}" to "{form.np.data}"'
print(cmd_str)
Output:
The old password for "form.un.data" is "form.op.data" The old password for "my.username" is "my.old.password"
Also, you don't need to provide the path to powershell.exe.
ok done a test and this works

import subprocess

un = "robert.wild"
op = "Password01!"
cnp = "Password2024!"
dom = "prod"

subprocess.run(f'powershell.exe write-host {un} {op} {cnp} {dom}', shell=True)
but when i put it in my script ie inbetween the lines of

return '<h1>The username is {}. The old password is {}. the new password is {}. changing for domain {}'.format(form.un.data, form.op.data, form.cnp.data, form.dom.data)
 subprocess.run(f'powershell.exe write-host {un} {op} {cnp} {dom}', shell=True)       
    return render_template('password.html', form=form)
it doesnt work
thanks dean, i will try this when get home and let you know how i get along
When you "return" in a function, you exit the function. Your return here:
return '<h1>The username is {}. The old password is {}. the new password is {}. changing for domain {}'.format(form.un.data, form.op.data, form.cnp.data, form.dom.data)
prevents ever getting here.
 subprocess.run(f'powershell.exe write-host {un} {op} {cnp} {dom}', shell=True)    
so where do you think i should put the subprocess command then as i want it to run as soon as they hit the submit button thats if all validation has passed
ok managed to get it to work

if request.method == 'POST' and form.validate():
        subprocess.run(f'powershell.exe write-host {form.un.data} {form.op.data} {form.cnp.data} {form.dom.data}', shell=True)
        return '<h1>The username is {}. The old password is {}. the new password is {}. changing for domain {}'.format(form.un.data, form.op.data, form.cnp.data, form.dom.data)
    return render_template('password.html', form=form)
Pages: 1 2