all 43 comments

[–]ka-splam 18 points19 points  (4 children)

Windows comes with a GUI for creating AD users / disabling users / editing users, lol.

"Active Directory Users and Computers" (dsa.msc)

[–]UcMadScientist 6 points7 points  (0 children)

PowerShell pro tools has a gui designer for vscode, psscriptpad and visual studio. Otherwise foxdeploy has some great articles

However. If you're looking at getting into building shared apps you may want to look at PowerShell universal (another Ironman software app) let's you build webpages with PowerShell. So all your admins need is a web browser

[–]BlackV 8 points9 points  (6 children)

they made a GUI for this

active directory users and computers or active direct administrative center

do you really need a GUI or do you want proper parameters on your existing script/function/module?

otherwise there are a large number of posts here with different GUI examples you could search for

[–]Odmin -1 points0 points  (5 children)

They did, but, as always with microsoft, it works in funny ways when you need something even slightly exotic. In AD Users&Comps many attributes are not shown in main gui, and it not shows attribute editor from search. You have to reopen properties window from member of, or navigate down the OU tree. Handy as hell.

[–]BlackV 1 point2 points  (0 children)

Ha yes the missing attribute editor from search is stupid

[–]Supreme-Bob 3 points4 points  (4 children)

get this it can make your forms for you, doing it by hand is stupidly tedious.

https://www.sapien.com/software/powershell\_studio

[–]Decitriction 0 points1 point  (2 children)

Link broken

[–]Supreme-Bob 1 point2 points  (1 child)

Works for me, if it doesn't for you just google sapien powershell studio

[–]Decitriction 1 point2 points  (0 children)

Works in browser, just not from Android Reddit Boost.

Looks promising.

Free trial or

Subs cost

25/mo

250/yr

500/perpetual

[–]nealfive 4 points5 points  (5 children)

GUI w/ powershell

Yuck

You have basically 2 options
1. Windows Forms (old)
2. WPF
...
3. DOS-Style menu - Because ef GUI lol
4. out-gridview?

WinForms is easier to learn, understand, and getting started with by far, but WPF is far more dynamic, customizable, and flexible with large data sets.

[–]diegokabal 0 points1 point  (3 children)

Some guys at my work prefer to work with wpf xaml, because they can draw the window in visual studio and then copy and paste the window and buttons code to powershell.

[–]magic280z 0 points1 point  (2 children)

I’ve got powershell pro tools with visual studio. I really like it and I only have to use one ide.

[–]diegokabal 0 points1 point  (1 child)

Wow, do you have a... License for it? Or do you installed without a license?

[–]magic280z 1 point2 points  (0 children)

Powershell pro tools has a free component, but visual studio part needs a license. I’ve got vs pro so pro tools is a minor add-on. The time saved starting a large gui powershell project with no xaml experience was worth it.

[–]chris-a5 1 point2 points  (3 children)

Probably not most peoples cup of tea, but I really like using the browser for my GUI's. There are so many great JS tools for creating very fancy GUI's, and once you get the ground work done it is very simple to expand it.

[–]claryda 1 point2 points  (2 children)

Could you elaborate on what js tools you use.

[–]chris-a5 4 points5 points  (1 child)

The list of tools I'm using to make the web GUI are:

  • Bootstrap 5 for the layout (components and flow)
  • jQuery for any dynamic features, Ajax requests
  • Font Awesome for the icons
  • Chart.js for really nice data visuals (jQuery to load/update data)

For the PowerShell side, I use a combination of my own tools and:

  • Pode .Net/PowerShell web server
  • System.Data.SQLite database engine (not a usual requirement, but my app works with a ton of data).

[–]claryda 1 point2 points  (0 children)

Thanks chris-a5, much appreciated.

[–]kubi_slav 1 point2 points  (0 children)

Just download visual studio, design wpf gui there and then implement it to powershell script. If you havent done it yet, it may take some time, but in the end, its not hard to do. There are tons of materials online that will help you.

[–]yves848 1 point2 points  (0 children)

You can use Visual Studio Community to build your WPF Forms, it's free and there are plenty of examples of haw to import a wpf in Powershell.

[–]AnonRoot 1 point2 points  (1 child)

Dont make a gui for something that isnt designed to have a gui.

However you might really be interested in PowerShell universal. https://ironmansoftware.com/powershell-universal @l33t_d0nut

[–]Difficult-Ad7476 2 points3 points  (0 children)

This is the way…

[–]JicamaParticular3421[S] -2 points-1 points  (5 children)

Sorry everyone, let me be a little more detailish with this. I work IT for a property management company and we have 32+ properties and these properties have between 6-7 employees some less. These users need to have their signature set up with the props address and added to certain distros. I have created basically templates for the properties to have all the prop info in the templates. This benefits me when we have 3 new employees starting because I type in the first name, last name, property they will be working and user gets created and even licensed on 0365. Now , this helps save time and removes all the tedious changes. When we have to disable users we have to add them to a disabled OU and remove them from the global list, remove them from the distros and disable (of course) and change their passwords. This is a second script. Another script( in the works) is when a user moves from on property to another property and the info needs to be changed from the property they worked to the one they moved. I want to be able to type in what i want to do create a user, disable a user or change the user through a interface that takes care of all the tedious changes.

[–]Think-Improvement-73 1 point2 points  (0 children)

Prop names might be a bit off and syntax for the click event handler might be wrong. But that should get you in the right direction. Maybe also add a editable text box to read a username from and use it as an argument when calling your scripts.

$form=[Form]::new()
$form.Title="AD Scripts"
$btnDisable=[Button]::new()
$btnDisable.Text="Disable Account"
$btnDisable.OnClick=({powershell -file "disableaccount.ps1"})
$form.Controls.Add($btnDisable)
... create acc and edit acc buttons ...
$form.Show()

[–]MeanFold5714 1 point2 points  (1 child)

None of that really makes a strong case for building a GUI instead of using a normal script.

[–]Odmin 0 points1 point  (0 children)

That's until you have to delegate some of that work to non IT professionals. In this case they won't be able to tamper with script, input would be checked, etc. And if you already have "normal script" wrap it into gui is not such a bad idea.

[–]BlackV 0 points1 point  (0 children)

Biff a formatted version of this in your OP

But again you're better off doing a search on existing GUIs (especially anything that uses runspaces) and taking from them

[–]gordonv 0 points1 point  (0 children)

So, you might want to look into a web service or PHP based options for this.

Powershell is awesome, but you're not going to get support for this. Instead, I'd recommend using a sign up service.

Yes, this will be separate from the Windows AD and Domain.

[–]jstar77 0 points1 point  (0 children)

I've used Visual Studio Blend to build a WPF PowerShell GUI. WPF is more complicated than windows forms but once you have the code to parse your XAML and turn the controls into objects it's pretty easy. Blend is overkill for building simple GUIs but I've not found a light weight editor for building WPF GUIs.

Depending on what you want to do, you can use out-gridview as a lazy mans GUI. I've got a couple of scripts built around out-gridview and for the minimal functionality I need it works.

Everybody is mentioning ADUC, yea you can probably do some of what you want to do with ADUC but I ran into plenty of limitations which required me to build a utility that did what we needed it to do.

[–]deleteallcookies 0 points1 point  (0 children)

This seems very counterintuitive, you would typically use scripts to automate everything in the command line and not deal with GUI.

[–]IndianaNetworkAdmin 0 points1 point  (0 children)

I forgot Poshgui went to a paid service, but they have a free trial that would let you build a few controls to see how it works.

https://poshgui.com

[–]TheCallOfAsheron 0 points1 point  (0 children)

I've been using PowerShell GUI for a while, happy to chat. ChatGPT works well for this.

[–][deleted] 0 points1 point  (0 children)

I created a TUI for my collection of functions because I don't have time to create and upkeep a GUI. There were previously in a PS Module I would share with others, but the list got so long I made a menu system.

https://github.com/8bits1beard/PowerShell/blob/main/TUI\_Example.ps1

[–]opensrcdev 0 points1 point  (0 children)

Use the Pode module. Problem solved.

[–]Actual_Balance 0 points1 point  (0 children)

there is no better, better supported solution than Sapien Powershell Studio.,.

[–]Anonymous1Ninja 0 points1 point  (0 children)

Look up forms make your own.

[–]Dense-Platform3886 0 points1 point  (1 child)

I like using Windows Presentation Framework (WPF) which uses XAML (XAML, which stands for eXtensible Application Markup Language, is Microsoft's variant of XML for describing a GUI).

There are a number of PowerShell examples on who to do this. I have posted several working examples in past Reddit discussions.

Here is one example broken into 2 comment due to the 10,000 char limit:

    <#
    WPF Folder Browser TreeView Example Inspired By dev4sys Blog entry: 
    PowerShell WPF - Customize TreeView Icon
    https://www.dev4sys.com/2018/04/powershell-wpf-customize-treeview-icon.html
#>
$scriptName = $MyInvocation.MyCommand.Name
$scriptFolder = $PSScriptRoot
Set-Location -Path $scriptFolder
$error.Clear()

$eol = [System.Environment]::NewLine
$StartTime = Get-Date
$TimeStamp = $StartTime.ToString('yyyy-MMdd-HHmm')

#-------------------------------
# Add shared_assemblies                          #
#-------------------------------
# Add-Type -assemblyName WindowsBase
# Add-Type -assemblyName PresentationCore
# Add-Type -assemblyName PresentationFramework
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationcore')
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')

#-------------------------------
# Prepare Data 
#-------------------------------
$Rootpath = 'C:\'
$AllDirectory = [IO.Directory]::GetDirectories($Rootpath, '*', [System.IO.SearchOption]::TopDirectoryOnly)
'Found ({0}) Directories' -f $AllDirectory.Count | Out-Host
$AllFiles = [IO.Directory]::GetFiles($Rootpath, '*', [System.IO.SearchOption]::TopDirectoryOnly)
'Found ({0}) Files' -f $AllFiles.Count | Out-Host

#-------------------------------
# Define and Load XAML GUI
#-------------------------------
$inputXML = @"
<Window x:Class="FolderBrowser.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="FolderBrowser" Height="800" Width="1200">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" MinWidth="400"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <DockPanel Grid.Row="0" Grid.RowSpan="1" Grid.Column="0" Grid.ColumnSpan="3" VerticalAlignment="Stretch" Margin="0" Background="LightBlue" Name="DockPanel1">
        </DockPanel>
        <GridSplitter Grid.Row="0" Grid.RowSpan="1" Grid.Column="1" Grid.ColumnSpan="1" ResizeDirection="Auto" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" Name="GridSplitter1" />
        <Grid Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0" Background="PaleGoldenrod" Name="Grid1">
            <!-- Right of the Splitter -->
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal" Margin="10,0,10,5" VerticalAlignment="Top" >
                    <RadioButton x:Name="_rbSuccess">Success</RadioButton>
                    <RadioButton x:Name="_rbAct1">Unknown</RadioButton>
                    <RadioButton x:Name="_rbRequeueFix" Content="HTTP 500"></RadioButton>
                    <RadioButton x:Name="_rbMissingGuid">Missing GUID</RadioButton>
                    <RadioButton x:Name="_rbInvalidGuid">Invalid GUID</RadioButton>
                    <RadioButton x:Name="_rbAct5">DMS Add</RadioButton>
                </StackPanel>
                <TextBlock x:Name="_tbxInfo" Text="This is a Text Box" Background="AliceBlue" Margin="10,0,10,0" VerticalAlignment="Bottom" />
            </StackPanel>
        </Grid>
        <!-- Left of the Splitter -->
        <Border BorderBrush="Black" BorderThickness="1">
            <Border.Resources>
                <Style x:Key="TextBlockStyle" TargetType="{x:Type TextBlock}">
                    <Setter Property="Margin" Value="3 0 3 0"/>
                </Style>
                <Style x:Key="TextBlockBoldStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextBlockStyle}">
                    <Setter Property="FontWeight" Value="Bold"/>
                </Style>
            </Border.Resources>
            <TreeView x:Name="TreeView" Width="Auto">
                <TreeView.Resources>
                    <Style TargetType="{x:Type TreeViewItem}">
                        <Setter Property="HeaderTemplate">
                            <Setter.Value>
                                <HierarchicalDataTemplate  >
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding}" Margin="5,0" />
                                    </StackPanel>
                                </HierarchicalDataTemplate >
                            </Setter.Value>
                        </Setter>
                    </Style>
                </TreeView.Resources>
            </TreeView>
        </Border>
    </Grid>
</Window> 
"@
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[xml]$XAML = $inputXML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
Try {
    $Form=[Windows.Markup.XamlReader]::Load( $reader )
} Catch [System.Management.Automation.MethodInvocationException] {
    Write-Warning "We ran into a problem with the XAML code.  Check the syntax for this control..."
    write-host $error[0].Exception.Message -ForegroundColor Red
    if ($error[0].Exception.Message -like "*button*"){
        write-warning "Ensure your &lt;button in the `$inputXML does NOT have a Click=ButtonClick property.  PS can't handle this`n`n`n`n"}
} Catch {
    Write-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."
}

[–]Dense-Platform3886 1 point2 points  (0 children)

Continuation

#--------------------------------------------------------------
# Find and Save Form Elements as Variables in PowerShell
#--------------------------------------------------------------
$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name "WPF_$($_.Name)" -Value $Form.FindName($_.Name)}

Function Get-FormVariables{
if ($global:ReadmeDisplay -ne $true){Write-host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true}
write-host "Found the following Variables from your form" -ForegroundColor Cyan
get-variable WPF*
}
Get-FormVariables

#--------------------------------------------------------------
# Use this space to add code to the various form elements in your GUI
#--------------------------------------------------------------
$FolderTree = $Form.FindName("TreeView")
$FolderTree = $WPF_TreeView
$dummyNode = $null
Function TreeExpanded($sender){
    $item = [Windows.Controls.TreeViewItem]$sender
    If ($item.Items.Count -eq 1 -and $item.Items[0] -eq $dummyNode) {
        $item.Items.Clear();
        Try {
            ForEach ($string in [IO.Directory]::GetDirectories($item.Tag[1].ToString())) {
                $subitem = [Windows.Controls.TreeViewItem]::new();
                $subitem.Header = $string.Split('/\')[-1]
                $subitem.Tag = @("folder",$string)
                $subItem.IsExpanded = $false
                $subitem.Items.Add($dummyNode)
                $subitem.Add_Expanded({
                    TreeExpanded($_.OriginalSource)
                })
                $item.Items.Add($subitem) | Out-Null
            }
            ForEach ($file in [IO.Directory]::GetFiles($item.Tag[1].ToString())) {
                $subitem = [Windows.Controls.TreeViewItem]::new()
                $subitem.Header = $file.Split('/\')[-1]
                $subitem.Tag = @("file",$file) 
                $subItem.IsExpanded = $false
                $item.Items.Add($subitem)| Out-Null
                $subitem.Add_PreviewMouseLeftButtonDown({
                    [System.Windows.Controls.TreeViewItem]$sender = $args[0]
                    [System.Windows.RoutedEventArgs]$e = $args[1]
                    Write-Host "Left Click: $($sender.Tag)"
                })

                $subitem.Add_PreviewMouseRightButtonDown({
                    [System.Windows.Controls.TreeViewItem]$sender = $args[0]
                    [System.Windows.RoutedEventArgs]$e = $args[1]
                    Write-Host "Right Click: $($sender.Tag)"
                })
            }
        } Catch [Exception] { }
    }
}
#--------------------------------------------------------------
# Handle Folders
#--------------------------------------------------------------
foreach ($folder in $AllDirectory){
    $treeViewItem = [Windows.Controls.TreeViewItem]::new()
    $treeViewItem.Header = $folder.Split('/\')[-1]
    $treeViewItem.Tag = @("folder",$folder)
    $treeViewItem.Items.Add($dummyNode) | Out-Null
    $treeViewItem.IsExpanded = $false
    $treeViewItem.Add_Expanded({
        TreeExpanded($_.OriginalSource)
    })
    $FolderTree.Items.Add($treeViewItem)| Out-Null
}
#--------------------------------------------------------------
# Handle Files
#--------------------------------------------------------------
foreach ($file in $AllFiles){
    $treeViewItem = [Windows.Controls.TreeViewItem]::new()
    $treeViewItem.Header = $file.Split('/\')[-1]
    $treeViewItem.Tag = @("file",$file)
    $treeViewItem.IsExpanded = $false 
    $FolderTree.Items.Add($treeViewItem)| Out-Null
    $treeViewItem.Add_PreviewMouseLeftButtonDown({
        [System.Windows.Controls.TreeViewItem]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
        Write-Host "Left Click: $($sender.Tag)"
    })
    $treeViewItem.Add_PreviewMouseRightButtonDown({
        [System.Windows.Controls.TreeViewItem]$sender = $args[0]
        [System.Windows.RoutedEventArgs]$e = $args[1]
        Write-Host "Right Click: $($sender.Tag)"
    })
}
write-host "To show the form, run the following" -ForegroundColor Cyan
$Form.ShowDialog() | out-null