Share via


Powershell to XAML - Button / Text Box Function

Question

Thursday, August 14, 2014 8:18 PM

I have a script I wanted to build into a GUI for support staff.  I created the XAML in Visual Studio 2013 Express, then pasted it into my PowerShell script.  I've been trying add / change the relevant code to make the script use the variable provided to the GUI, then start the script with the button is pressed, but it seems to skip over my button each time using a blank variable (which would have been disastrous if run on a prod system!)

Can anyone point me to the problem(s) with my script changes?

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @'
<Window Name="DeleteProfiles_Citrix"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Delete Citrix User Profile" Height="391.791" Width="369.776">
    <Grid Name="DeleteProfiles_Citrix1">
        <Label Content="Citrix User Name" HorizontalAlignment="Left" Margin="37,28,0,0" VerticalAlignment="Top" Width="102"/>
        <TextBox Name="txtUser" HorizontalAlignment="Left" Height="23" Margin="180,31,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="138" ToolTip="ex. ASMITH"/>
        <Button Name="btnSubmit" Content="Delete Citrix User Profile" HorizontalAlignment="Left" Margin="180,74,0,0" VerticalAlignment="Top" Width="138"/>
        <Button Name="btnExit" Content="Close" HorizontalAlignment="Left" Margin="277,331,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBox Name="txtOutput" HorizontalAlignment="Left" Height="186" Margin="10,134,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="342"/>
        <Label Content="Output" HorizontalAlignment="Left" Margin="10,108,0,0" VerticalAlignment="Top"/>

    </Grid>
</Window>
'@

$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."; exit}
#Form Objects
$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}
#Events to Form Objects
$btnExit.Add_Click({$form.Close()})
$btnSubmit.Add_Click({
    $script:var = $txtUser.Text.ToString()
    })
$txtUser.Text = $User
# Show the form
$Form.ShowDialog() | out-null

#===========================================================================

$CTXProfPath = "\\TEST3\Users"
$PServers = @("TEST1","TEST2")


foreach ($server in $PServers) {
   try { 
      Foreach ($Profile in (Get-WmiObject Win32_UserProfile -Computername $server | Where {$_.LocalPath -match "(c:\\users\\$user)(?![a-zA-Z0-9- _])"})) {
         try {
            $objSID = New-Object System.Security.Principal.SecurityIdentifier($Profile.SID)
            $CurUser = ($objSID.Translate([System.Security.Principal.NTAccount])).Value
            Write-UI "Deleting Profile for $CurUser"
            $Profile.Delete()
            Write-UI "$CurUser Profile Deleted"
            $TargetRoot = "\\$server\c`$\Users"
            Foreach ($LPath in (Get-ChildItem $TargetRoot | Where {$_.Name -match "($user)(?![a-zA-Z0-9- _])"})) {
           takeown /f $LPath.FullName /r /d y | Out-Null
               Write-UI "Deleting $($LPath.FullName)"
           Remove-Item $LPath.FullName -Recurse -Force
               Write-UI "$($LPath.FullName) $(If(Test-Path $LPath.FullName){"NOT DELETED"}Else{"DELETED"})"            }

            Write-UI "$CurUser profile and $($Profile.LocalPath) directory deleted successfully on $Server"
         } catch {
            Write-UI "Error For $CurUser on $Server - Error $($_.Exception.Message)"
         }
      } 
   } catch {
      Write-UI "Error For $user on $Server - Error $($_.Exception.Message)"
   }
}
Try {
   Foreach ($Path in (Get-ChildItem $CTXProfPath | Where {$_.Name -match "($user)(?![a-zA-Z0-9- _])"})) {
      takeown /f $Path.FullName /r /d y | Out-Null
      Write-UI "Deleting $($Path.FullName)"
      Remove-Item $Path.FullName -Recurse -Force
      Write-UI "$($Path.FullName) $(If(Test-Path $Path.FullName){"NOT DELETED"}Else{"DELETED"})"   }
} catch {
   Write-UI "Error Removing Folders from $CTXProfPath - Error $($_.Exception.Message)"
}

Thanks!

-Matt

There's no place like 127.0.0.1

All replies (7)

Friday, August 15, 2014 6:52 AM ✅Answered

Hi Matt,

To provide the variable from UI to powershell script, the sctipt below for your reference:

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = @'
<Window Name="DeleteProfiles_Citrix"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Delete Citrix User Profile" Height="391.791" Width="369.776">
    <Grid Name="DeleteProfiles_Citrix1">
        <Label Content="Citrix User Name" HorizontalAlignment="Left" Margin="37,28,0,0" VerticalAlignment="Top" Width="102"/>
        <TextBox Name="txtUser" HorizontalAlignment="Left" Height="23" Margin="180,31,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="138" ToolTip="ex. ASMITH"/>
        <Button Name="btnSubmit" Content="Delete Citrix User Profile" HorizontalAlignment="Left" Margin="180,74,0,0" VerticalAlignment="Top" Width="138"/>
        <Button Name="btnExit" Content="Close" HorizontalAlignment="Left" Margin="277,331,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBox Name="txtOutput" HorizontalAlignment="Left" Height="186" Margin="10,134,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="342"/>
        <Label Content="Output" HorizontalAlignment="Left" Margin="10,108,0,0" VerticalAlignment="Top"/>

    </Grid>
</Window>
'@


$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}
#Events to Form Objects
$btnExit.Add_Click({$form.Close()})
$btnSubmit.Add_Click({
    $Form.Hide()
    $script:User = $txtUser.Text.ToString()
    })

$Form.ShowDialog() | out-null

$User

If there is anything else regarding this script, please feel free to let me know.

If you have any feedback on our support, please click here.

Best Regards,

Anna Wang

TechNet Community Support


Friday, August 15, 2014 5:35 PM ✅Answered

That's kind of what I was running into and fearing.  Maybe using WAF was the wrong choice for this.  Maybe I should look into executing these commands from a C#/C++ runspace instead?

There's no place like 127.0.0.1

You should look at using PowerShell runspaces to send those scriptblocks to do their work. You can then followup in your scriptblock using the dispatcher of a WPF control to update the UI.

Reference:

http://learn-powershell.net/2012/10/14/powershell-and-wpf-writing-data-to-a-ui-from-a-different-runspace/

Boe Prox
Blog | Twitter
PoshWSUS | PoshPAIG | PoshChat | PoshEventUI
PowerShell Deep Dives Book


Friday, August 15, 2014 3:30 PM

Thanks!  That worked great.

It did however reveal how badly the rest of my ties to the XAML were written though :)

I thought I had written it so the output would go to the bottom text box, instead of the PowerShell console.  Instead it closes the GUI and dumps to the console.

Any advise on how to get the output to that text box, and not close the GUI until the close button is pressed?

There's no place like 127.0.0.1


Friday, August 15, 2014 3:49 PM | 1 vote

$btnSubmit.Add_Click({
#    $Form.Hide()
    $script:User = $txtUser.Text.ToString()
    $txtOutput.Text = $user
    })

I commented the $Form.Hide() because then you wouldn't see anything anyway.

I hope this post has helped!


Friday, August 15, 2014 4:27 PM

Yes the form stays open now.  Unfortunately it stops my script until the form is closed.  I want this to stay open while the script runs so results could be fed back to the text window.  Do I have some kind of pause coded here?

There's no place like 127.0.0.1


Friday, August 15, 2014 4:49 PM

If you keep the $form.hide() that will return control to the script but then there's not much reason to show the choice.  The 'Close' button is perhaps mislabelled as it is coded to behave more like a 'Submit' button.  I don't think you can keep the window open, but you can hide and showdialog after script operations to show details in the output box.  But as far as using it as a monitoring and progress dialog I think you're out of luck.  For example:

$btnSubmit.Add_Click({
#    $Form.Hide()
    $script:User = $txtUser.Text.ToString()
    $txtOutput.Text = $user
    Start-Sleep -s 2
    $txtOutput.Text = "$user displayed for 2 seconds"
    Start-Sleep -s 2    $txtOutput.Text = "$user displayed for 2 more seconds"
    })

The above code shows several script actions.  The problem is that the contents of $txtOutput won't actually be displayed until that script block is complete, so you would only get the final message.  Maybe someone else knows how to keep the dialog open and displaying script outputs.

I hope this post has helped!


Friday, August 15, 2014 5:01 PM

That's kind of what I was running into and fearing.  Maybe using WAF was the wrong choice for this.  Maybe I should look into executing these commands from a C#/C++ runspace instead?

There's no place like 127.0.0.1