我无法让“同步文件夹”功能在运行时输出到文本框。我尝试在网上查找许多指南,包括在此处进行搜索,但无法弄清楚。我希望能比我更了解这一点的人在下面的测试示例中向我展示如何做到这一点:
$Global:syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
# Load WPF assembly if necessary
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
$psCmd = [PowerShell]::Create().AddScript({
[xml]$xaml = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestApp" Height="450" Width="800">
<Grid>
<Button x:Name="runButton" Content="Run" HorizontalAlignment="Left" Margin="293,37,0,0" VerticalAlignment="Top" Width="189" Height="40"/>
<TextBox x:Name="textbox" TextWrapping="NoWrap" FontFamily="Consolas" ScrollViewer.VerticalScrollBarVisibility="Auto" IsReadOnly="True" Margin="10,137,10,10"/>
</Grid>
</Window>
"@
# 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) )
}
$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
#=========================================
#=========================================
#=========================================
#================= runButton =============
$syncHash.runButton.Add_Click({
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("SyncHash",$SyncHash)
$PowerShell = [PowerShell]::Create().AddScript({
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")
}
#============== START stuff to do =================
function sync-folder {
function timestamp {
$timestamp = "$(Get-Date -f 'yyyy-MM-dd HH:mm:ss:fff')"
Write-Output "$timestamp "
}
$MainLog = "C:\ProgramData\test\Logs\Main_Log.txt"
$SyncLog = "C:\ProgramData\test\Logs\Sync_Log.txt"
$RemoteSync = "\\remote\sync\path\test"
$RobocopySource = "\\remote\location\"
$RobocopyDestination = "C:\ProgramData\test"
# Check if Log exists...
# If not exist, then create it:
If (!(Test-Path $MainLog)) {
# Create MainLog.txt
New-Item -ItemType File -Force $MainLog
# Write to log:
Write-Output "$(timestamp) Main Log File has been created." >> $MainLog
}
If (!(Test-Path $SyncLog)) {
# Create MainLog.txt
New-Item -ItemType File -Force $SyncLog
# Write to log:
Write-Output "$(timestamp) Sync Log File has been created." >> $SyncLog
}
if (Test-Path $RemoteSync) {
Write-Output "$(timestamp) Sync location is reachable. Starting sync..." >> $MainLog
Write-Output "$(timestamp) Sync location is reachable. Starting sync..." >> $SyncLog
robocopy $RobocopySource $RobocopyDestination /MIR /FFT /R:3 /W:10 /NP /NDL /UNILOG+:$SyncLog
Write-Output "$(timestamp) Sync complete. Check $SyncLog for details." >> $MainLog
Write-Output "$(timestamp) Sync complete." >> $SyncLog
exit
} else {
Write-Output "$(timestamp) Sync location is NOT reachable. Synchronization aborted..." >> $MainLog
Write-Output "$(timestamp) Exiting SYNC Task..." >> $MainLog
Write-Output "$(timestamp) Sync location NOT reachable. Synchronization aborted..." >> $SyncLog
Write-Output "$(timestamp) Exiting SYNC Task..." >> $SyncLog
exit
}
}
sync-folder
#============== END stuff to do ===================
})
$PowerShell.Runspace = $newRunspace
[void]$Jobs.Add((
[pscustomobject]@{
PowerShell = $PowerShell
Runspace = $PowerShell.BeginInvoke()
}
))
})
$syncHash.Window.Add_Closed({
Write-Verbose 'Halt runspace cleanup job processing'
$jobCleanup.Flag = $False
#Stop all runspaces
$jobCleanup.PowerShell.Dispose()
})
$syncHash.Window.ShowDialog() | Out-Null
$syncHash.Error = $Error
})
#=====================================
# Shows the form
#=====================================
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()