我正在编写的工具包遇到了一个新的绊脚石。到目前为止,我已经设法处理带有数组的复选框并切换大小写以处理后续命令。但是,我有几件事需要用户输入,我想通过TextBox来获取它,到目前为止,我无法做到这一点。
主要程序代码:
$ScriptRoot = $pwd.Path
$ScriptRoot
$Functionsfile = "$ScriptRoot" + "\Functions.ps1"
. $Functionsfile
$Global:Return
$Global:syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$newRunspace.SessionStateProxy.SetVariable("Functionsfile",$Functionsfile)
$newRunspace.SessionStateProxy.SetVariable("Scriptroot",$ScriptRoot)
# Load WPF assembly if necessary
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
$psCmd = [PowerShell]::Create().AddScript({
[xml]$xaml = @"
<Window x:Name="Main_Form" x:Class="UnattendCheck.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UnattendCheck"
mc:Ignorable="d"
Title="Unattend Check" Height="413.414" Width="509.756" Background="#FFEAEAEA">
<Grid Margin="0,0,2,1">
<Label x:Name="ContactLabel" Content="Select Techs to contact on Failure" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Email1ChBox" Content="Ben Church" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Email2ChBox" Content="Dustin Klingele" HorizontalAlignment="Left" Margin="10,56,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Email3ChBox" Content="Brian Oitker" HorizontalAlignment="Left" Margin="10,71,0,0" VerticalAlignment="Top"/>
<Label x:Name="OptionsLabel" Content="Options" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Option1ChBox" Content="OptiPlex 755" HorizontalAlignment="Left" Margin="221,41,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Option2ChBox" Content="F216 Lab" HorizontalAlignment="Left" Margin="221,56,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Option3ChBox" Content="F105 Lab" HorizontalAlignment="Left" Margin="221,71,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="Option4ChBox" Content="Email on completion" HorizontalAlignment="Left" Margin="221,86,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="OutputBox" HorizontalAlignment="Left" Height="196" Margin="10,162,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="480" Text="Output Logging"/>
<Button x:Name="StartBtn" Content="Start" HorizontalAlignment="Left" Margin="415,137,0,0" VerticalAlignment="Top" Width="75"/>
<TextBox x:Name="DesignationBox" HorizontalAlignment="Left" Height="23" Margin="10,134,0,0" TextWrapping="Wrap" Text="Designation" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="StartNumberBox" HorizontalAlignment="Left" Height="23" Margin="135,134,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="45" Text="First #"/>
<TextBox x:Name="EndNumberBox" HorizontalAlignment="Left" Height="23" Margin="185,134,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="45" Text="Last #"/>
<PasswordBox x:Name="PasswordBox" HorizontalAlignment="Left" Margin="370,109,0,0" VerticalAlignment="Top" Width="120" Height="23"/>
<TextBox x:Name="UsernameBox" HorizontalAlignment="Left" Height="23" Margin="370,56,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label x:Name="PasswordLabel" Content="Password:" HorizontalAlignment="Left" Margin="365,83,0,0" VerticalAlignment="Top"/>
<Label x:Name="UsernameLabel" Content="Username:" HorizontalAlignment="Left" Margin="365,30,0,0" VerticalAlignment="Top"/>
<Label x:Name="CredLabel" Content="Enter credentials for email." HorizontalAlignment="Left" Margin="339,10,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>
"@
# Variables
$Emails = @($null, $null, $null)
$Options = @($null, $null, $null, $null)
#Tech emails
$email1 = 'butter@butterzone.com'
$email2 = 'margarine@butterzone.com'
$email3 = 'pad@butterzone.com'
. $Functionsfile
Process-XML
$Script:JobCleanup = [hashtable]::Synchronized(@{})
$Script:Jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
#region Background runspace to clean up jobs
$jobCleanup.Flag = $True
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("jobCleanup",$jobCleanup)
$newRunspace.SessionStateProxy.SetVariable("jobs",$jobs)
$jobCleanup.PowerShell = [PowerShell]::Create().AddScript({
#Routine to handle completed runspaces
Do {
Foreach($runspace in $jobs) {
If ($runspace.Runspace.isCompleted) {
[void]$runspace.powershell.EndInvoke($runspace.Runspace)
$runspace.powershell.dispose()
$runspace.Runspace = $null
$runspace.powershell = $null
}
}
#Clean out unused runspace jobs
$temphash = $jobs.clone()
$temphash | Where {
$_.runspace -eq $Null
} | ForEach {
$jobs.remove($_)
}
Start-Sleep -Seconds 1
} while ($jobCleanup.Flag)
})
$jobCleanup.PowerShell.Runspace = $newRunspace
$jobCleanup.Thread = $jobCleanup.PowerShell.BeginInvoke()
#endregion Background runspace to clean up jobs
<#Start of checkbox processing #>
<#Emails #>
$syncHash.Email1ChBox.Add_Click({
If ( $Emails[0] -ne $email1 ) {
$Emails[0] = $email1
}
Else { $Emails[0] = $null }
})
$syncHash.Email2ChBox.Add_Click({
If ( $Emails[1] -ne $email2 ) {
$Emails[1] = $email2
}
Else { $Emails[1] = $null }
})
$syncHash.Email3ChBox.Add_Click({
If ( $Emails[2] -ne $email3 ) {
$Emails[2] = $email3
}
Else { $Emails[2] = $null }
})
<# Option Items #>
$syncHash.Option1ChBox.Add_Click({
If ( $Options[0] -ne "755" ) {
$Options[0] = "755"
}
Else { $Options[0] = $null }
})
$syncHash.Option2ChBox.Add_Click({
If ( $Options[1] -ne "F216" ) {
$Options[1] = "F216"
}
Else { $Options[1] = $null }
})
$syncHash.Option3ChBox.Add_Click({
If ( $Options[2] -ne "F105" ) {
$Options[2] = "F105"
}
Else { $Options[2] = $null }
})
$syncHash.Option4ChBox.Add_Click({
If ( $Options[3] -ne "Success" ) {
$Options[3] = "Success"
}
Else { $Options[3] = 0 }
})
$syncHash.UsernameBox.TextChanged({
$Username = $syncHash.UsernameBox.Text
})
$syncHash.StartBtn.Add_Click({ # The big red button.
#Start-Job -Name Sleeping -ScriptBlock {start-sleep 5}
#while ((Get-Job Sleeping).State -eq 'Running'){
$x+= "."
#region Boe's Additions
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("SyncHash",$SyncHash)
$newRunspace.SessionStateProxy.SetVariable("Emails",$Emails)
$newRunspace.SessionStateProxy.SetVariable("Functionsfile",$Functionsfile)
$newRunspace.SessionStateProxy.SetVariable("Options",$Options)
$newRunspace.SessionStateProxy.SetVariable("Scriptroot",$ScriptRoot)
$newRunspace.SessionStateProxy.SetVariable("Username",$Username)
$PowerShell = [PowerShell]::Create().AddScript({
$names = @("Ah ah ah... You didn't say the magic word...", $null, $null)
. $Functionsfile
$synchash.PasswordBox
$counter = 0
While ( $counter -lt 5 ) {
$counter++
$output = $output + $names[0]
Update-Window -Control OutputBox -Property Text -Value $output
$output = $output + "`n"
}
$text = $syncHash.UsernameBox.GetLineText()
Update-Window -Control OutputBox -Property Text -Value $Username
#Update-Window -Control OutputBox -Property Text -Value $syncHash.UsernameBox
<#
$Cred = New-Object System.Management.Automation.PSCredential($synchash.UsernameBox.Text,$synchash.PasswordBox.SecurePassword)
Email "Unattend complete." "Computername has finished the unattend. If it needs anything else you can go do that now." -InputList $Emails $Cred
#>
})
$PowerShell.Runspace = $newRunspace
[void]$Jobs.Add((
[pscustomobject]@{
PowerShell = $PowerShell
Runspace = $PowerShell.BeginInvoke()
}
))
})
#region Window Close
$syncHash.Window.Add_Closed({
Write-Verbose 'Halt runspace cleanup job processing'
$jobCleanup.Flag = $False
#Stop all runspaces
$jobCleanup.PowerShell.Dispose()
})
#endregion Window Close
#endregion Boe's Additions
#$x.Host.Runspace.Events.GenerateEvent( "TestClicked", $x.test, $null, "test event")
#$syncHash.Window.Activate()
$syncHash.Window.ShowDialog() | Out-Null
$syncHash.Error = $Error
})
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()
Functions.ps1代码
Function Update-Window () {
Param (
$Control,
$Property,
$Value,
[switch]$AppendContent
)
# This is kind of a hack, there may be a better way to do this
If ($Property -eq "Close") {
$syncHash.Window.Dispatcher.invoke([action]{$syncHash.Window.Close()},"Normal")
Return
}
# This updates the control based on the parameters passed to the function
$syncHash.$Control.Dispatcher.Invoke([action]{
# This bit is only really meaningful for the TextBox control, which might be useful for logging progress steps
If ($PSBoundParameters['AppendContent']) {
$syncHash.$Control.AppendText($Value)
} Else {
$syncHash.$Control.$Property = $Value
}
}, "Normal")
}
Function Read-Textbox(){
write-host "`nBegin Read-Textbox [$(get-date)]"
$SyncHash.UsernameBox.Dispatcher.Invoke($Normal,[action]{$Global:Return = $SyncHash.UsernameBox.Text})
$Global:Return
remove-variable -Name Return -scope Global
write-host "End Read-Textbox [$(get-date)]"
}
Function Process-XML () {
# Remove XML attributes that break a couple things.
# Without this, you must manually remove the attributes
# after pasting from Visual Studio. If more attributes
# need to be removed automatically, add them below.
$AttributesToRemove = @(
'x:Class',
'mc:Ignorable'
)
foreach ($Attrib in $AttributesToRemove) {
if ( $xaml.Window.GetAttribute($Attrib) ) {
$xaml.Window.RemoveAttribute($Attrib)
}
}
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
[xml]$XAML = $xaml
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | %{
#Find all of the form types and add them as members to the synchash
$syncHash.Add($_.Name,$syncHash.Window.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 interactable elements from our form" -ForegroundColor Cyan
get-variable WPF*
}
# Functions for UnattendCheck, can be used elsewhere.
Function Email([string]$subject,[string]$message,$Addresses,$Cred) {
$mailparam = @{
To = $Addresses
From = $useremail
Subject = $subject
Body = $message
SmtpServer = 'smtp.office365.com'
Port = '587'
Credential = $Cred
}
Send-MailMessage @mailparam -UseSsl
}
Function unattendcheck {
[string]$user = '*inst*'
<# This checks for the existence of end.txt, if it exists... #>
If (Test-Path \\$computername\C$\install\end.txt) {
<# If install user is no longer signed in and the end.txt exists, we are done. Probably. #>
If ($active -eq 0) {
IF ( $email_notify -eq 1 ) {
email "Unattend complete." "$computername has finished the unattend. If it needs anything else you can go do that now."
}
Write-Host "$computername has finished unattending."
$active = 0
$endcounter = 0
$counter = 0
$query = $null
exit 0
}
} ElseIf (-Not (Test-Path \\$computername\C$\install\end.txt)) {
If ( -NOT ( $counter -eq 0 ) -AND $counter -le 12 -OR $active -eq 1 ) {
<# If the install user was signed in or not, we wait 5 minutes and check again.
If after 60 minutes we haven't seen the install user, we exit with a fault message. #>
Start-Sleep $timer
$counter++
If ( $counter -eq 6 -AND $active -eq 0 ) {
email "Unattend failure on $computername" "There appears to be a failure on $computername during unattend. The install user never signed in."
Write-Host "There appears to be a failure on $computername during unattend. The install user never signed in."
exit 88
} ElseIf ( $counter -eq 12 -AND $active -eq 1 ) {
email "Unattend failure on $computername" "$computername appears to have gotten stuck. Go check on it."
Write-Host "$computername appears to have gotten stuck. Go check on it."
exit 1864
}
unattendcheck
} Else {
<# If we cannot find the end.txt file, we assume the unattend
is still going, and we wait 90 minutes before checking again. #>
($query = query user /server:$computername) 2>&1 | out-null
<# Check for the install user being signed in.... #>
<# Set it as active and reset counter to prevent premature ending of script. #>
If ( $query -like $user ) {
$active = 1
If ( $endcounter -eq 0 ) {
$endcounter = 1
$counter = 0
}
} else { $active=0 ; Write-Host "Install user not active yet, will check back in 30 minutes."}
Start-Sleep 2700
$counter = 1
$timer = 300
unattendcheck
}
}
}
这是我目前最后一次尝试获得东西的方法。如果将“输出”框更改为$ syncHash.UsernameBox,它将显示System.Windows.Controls.TextBox:作为其输出,这意味着从某种意义上讲它可以拉取值,但是当我将其输出为字符串时,我在任何地方返回的值中都看不到它。
如果我能解决这个问题,那么这将使我向前迈进,因为我所有的底层代码都在标准控制台版本中工作,因此我只需要通过对GUI表单的更改来适应它即可。