启动从服务器到远程计算机的 powersehell 脚本

Launch powersehell script from server to remote computer

提问人:The Nurse 提问时间:8/27/2021 更新时间:8/27/2021 访问量:82

问:

我正在尝试将命令从服务器发送到计算机,这些命令将启动网络共享中的powershell脚本。

我尝试启动的脚本必须用于更新某些内容,但它显示 à 进度条以查看启动脚本中操作的演变。

我想做的是我想将该脚本启动到计算机,但我想从我的服务器查看进度条状态(用户将一无所获),winrm 已启用,我使用此命令从远程启动脚本:

$machine = computer01
$script = {
        param($Global:SCCM)
       & "\\$Global:SCCM\MajPoliciesSCCM.ps1"
        }
        Invoke-Command -ComputerName $machine -ScriptBlock $script -ArgumentList $Global:SCCM 

$Global:SCCM 是包含 powershell 脚本(带进度条)的服务器的变量。

我不知道是否可以从我的服务器看到进度条状态,因为我认为如果脚本启动到我的计算机 01,该状态将出现在这台机器上。

有可能这样做吗?

这是我的带有进度条的代码:

#Assembly.
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")


$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"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="Mise à jours des stratégies du client SCCM" Height="350" Width="525">
    <Grid Background="#68BFDD">
        <TextBlock x:Name="textBlock" HorizontalAlignment="center" Height="62" Margin="30" TextWrapping="Wrap" Text="Barre de progression" FontWeight="Bold" UseLayoutRounding="True" VerticalAlignment="Top" Width="200" Foreground="White" FontSize="18.667"/>
        <Button x:Name="button" Content="Exécuter" FontWeight="Bold" HorizontalAlignment="Left" Height="50" Margin="322,-60,0,0"  Width="114">
            <Button.Effect>
                <DropShadowEffect BlurRadius="15" ShadowDepth="0"/>
            </Button.Effect>
            <Button.Resources>
                <Style TargetType="{x:Type Border}">
                    <Setter Property="CornerRadius" Value="5"/>
                    <Setter Property="Padding" Value="10,2,10,3"/>
                    <Setter Property="Background" Value="White"/>
                </Style>
            </Button.Resources>          
        </Button> 
        <Button x:Name="button2" Content="Fermer" FontWeight="Bold" HorizontalAlignment="Left" Height="50" Margin="322,100,0,0"  Width="114"  Style="{DynamicResource RoundCorner}" IsCancel="True"  Command="{Binding CloseWindowCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=TestWindow}">
            <Button.Effect>
                <DropShadowEffect BlurRadius="15" ShadowDepth="0"/>
            </Button.Effect>
            <Button.Resources>
                <Style TargetType="{x:Type Border}">
                    <Setter Property="CornerRadius" Value="5"/>
                    <Setter Property="Padding" Value="10,2,10,3"/>
                    <Setter Property="Background" Value="White"/>
                </Style>
            </Button.Resources>          
        </Button> 

        <ProgressBar x:Name = "ProgressBar" Height = "20" Width = "400" HorizontalAlignment="Left" VerticalAlignment="Top" Margin = "36,270,0,0"/>
        <TextBlock x:Name="heartbeat" HorizontalAlignment="Left" Height="23" Margin="10,108,0,0" VerticalAlignment="Top" Width="161" FontSize="12" FontWeight="Bold" >
            Lancement du HeartBeat
        </TextBlock>
        
        <TextBlock x:Name="startordieval" HorizontalAlignment="Left" Height="35" Margin="10,136,0,0" VerticalAlignment="Top" Width="201" FontSize="12" FontWeight="Bold" >
            Strategie ordinateur et cycle <LineBreak/> d'évaluation
        </TextBlock>

        <TextBlock x:Name="cycleEvalLog" HorizontalAlignment="Left" Height="23" Margin="10,175,0,0" VerticalAlignment="Top" Width="240" FontSize="12" FontWeight="Bold" >
            Déploiements de mises à jours logiciels
        </TextBlock>
        
        <TextBlock x:Name="cycleevalappli" HorizontalAlignment="Left" Height="35" Margin="10,200,0,0" VerticalAlignment="Top" Width="161" FontSize="12"  FontWeight="Bold" >
            Cycle d'evaluation du <LineBreak/>déploiement de l'application
        </TextBlock>

        <TextBlock x:Name="EndScript" HorizontalAlignment="Left" Height="23" Margin="10,240,0,0" TextWrapping="Wrap" Text="Fin du script" VerticalAlignment="Top" Width="111" FontSize="12" FontWeight="Bold"/>
       
    </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

    $syncHash.button.Add_Click({
        #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) 
        $PowerShell = [PowerShell]::Create().AddScript({

Function write-log{            
##----------------------------------------------------------------------------------------------------            
##  Function: Write-Log            
##  Purpose: This function writes trace32 log fromat file to user desktop      
##  Function by: Kaido Järvemets Configuration Manager MVP (http://www.cm12sdk.net)
##----------------------------------------------------------------------------------------------------                            
PARAM(                     
    [String]$Message,                                  
    [int]$severity,                     
    [string]$component                     
    )                                          
    $TimeZoneBias = Get-WmiObject -Query "Select Bias from Win32_TimeZone"                     
    $Date= Get-Date -Format "HH:mm:ss.fff"                     
    $Date2= Get-Date -Format "MM-dd-yyyy"                     
    $type=1                         
   
    "<![LOG[$Message]LOG]!><time=$([char]34)$date+$($TimeZoneBias.bias)$([char]34) date=$([char]34)$date2$([char]34) component=$([char]34)$component$([char]34) context=$([char]34)$([char]34) type=$([char]34)$severity$([char]34) thread=$([char]34)$([char]34) file=$([char]34)$([char]34)>"| Out-File -FilePath "C:\windows\MAJPolicies_SCCM.Log" -Append -NoClobber -Encoding default            
    } 


#On récupère le nom de la machine via les variables d'environnement
$machine=computer01

write-log -Message "-+-+-+-+-+-+-+-+Debut du script MAJPolicies_SCCM+-+-+-+-+-+-+-+-+" -severity 1 -component "Strategies SCCM"


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")
    }                        


#Lancement du HeartBeat
$HearBeat = '{00000000-0000-0000-0000-000000000003}'|% {Invoke-WMIMethod -ComputerName $machine -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule $_} -ErrorAction SilentlyContinue

#On lance le Heartbeat, si c'est OK il fera les autres actions sinon il se stoppera
if ($HearBeat)
    {
    Update-Window -Control heartbeat -Property ForeGround -Value green                                                       
    start-sleep -Milliseconds 850
    #$x += 1..15000000
    update-window -Control ProgressBar -Property Value -Value 25
    #Le log se trouve dans "C:\Windows\CCM\Logs\InventoryAgent.log"
    write-log -Message "Lancement du HeartBeat" -severity 1 -component "Heartbeat"

    #update-window -Control TextBox -property text -value $x -AppendContent
    Update-Window -Control startordieval -Property ForeGround -Value green                                                     
    start-sleep -Milliseconds 850
    update-window -Control ProgressBar -Property Value -Value 50

    #Stratégie ordinateur + cycle d'évaluation
    sleep -Milliseconds 500
    #Les logs se trouvent dans "C:\Windows\CCM\Logs\PolicyAgent.log" et "C:\Windows\CCM\Logs\PolicyEvaluator.log"
    '{00000000-0000-0000-0000-000000000021}','{00000000-0000-0000-0000-000000000022}'|% {Invoke-WMIMethod -ComputerName $machine -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule $_} | Out-Null
    write-log -Message "Recuperation de strategie ordinateur et cycle d'evaluation" -severity 1 -component "Strategie ordinateur et cycle eval"

    
    Update-Window -Control cycleEvalLog -Property ForeGround -Value green                                                       
    start-sleep -Milliseconds 500
    update-window -Control ProgressBar -Property Value -Value 75
       
    #MAJ logiciels
    sleep -Milliseconds 500
    #Le log se trouve dans "C:\Windows\CCM\Logs\UpdatesDeployment.log"
    '{00000000-0000-0000-0000-000000000108}'|% {Invoke-WMIMethod -ComputerName $machine -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule $_} | Out-Null
    write-log -Message "Cycle d'evaluation des deploiements de mises a jours logiciels" -severity 1 -component "Eval deploiemen maj"

    Update-Window -Control cycleevalappli -Property ForeGround -Value green                                                       
    start-sleep -Milliseconds 200
    update-window -Control ProgressBar -Property Value -Value 80

        
    #Lancement policies Déploiement applications
    sleep -Milliseconds 500
    #Le log se trouve dans "C:\Windows\CCM\Logs\AppIntentEval.log"
    '{00000000-0000-0000-0000-000000000121}'|% {Invoke-WMIMethod -ComputerName $machine -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule $_} | Out-Null
    write-log -Message "Cycle d'evaluation du deploiement de l'application" -severity 1 -component "Eval deploiemen appli"

    Update-Window -Control EndScript -Property ForeGround -Value green                                                       
    start-sleep -Milliseconds 200
    update-window -Control ProgressBar -Property Value -Value 100    
    
    }
else 
{
write-log -Message "Lancement du HeartBeat négatif" -severity 1 -component "Heartbeat"
write-log -Message "Merci de vérifier le client SCCM" -severity 1 -component "Client SCCM"
Update-Window -Control heartbeat -Property ForeGround -Value red
Update-Window -Control startordieval -Property ForeGround -Value red
Update-Window -Control cycleEvalLog -Property ForeGround -Value red
Update-Window -Control cycleevalappli -Property ForeGround -Value red                                                         
Update-Window -Control EndScript -Property ForeGround -Value red
start-sleep -Milliseconds 200
Update-Window -Control ProgressBar -Property Value -Value 100
}


write-log -Message "-+-+-+-+-+-+-+-+Fin du script MAJPolicies_SCCM+-+-+-+-+-+-+-+-+" -severity 1 -component "Strategies SCCM"

        })
        $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()
WPF PowerShell 脚本进度 远程执行

评论

0赞 Seth 8/27/2021
据我所知,您实际上已经编写了一个 .NET 应用程序。你要问的是,什么时候可以在你这边显示该GUI的某些部分?如果你现在运行它,实际上会发生什么?
0赞 The Nurse 8/27/2021
是的,我想走到最后。当我运行脚本时,我看到脚本已经启动,但我的服务和我所针对的计算机上没有任何内容。我尝试在 C:\TEMP 上复制脚本,但什么都没有......这是我的测试代码:$script = { powershell "c:\TEMP\MajPoliciesSCCM.ps1" #or & "c:\TEMP\MajPoliciesSCCM.ps1" = same result test-path "c:\TEMP\MajPoliciesSCCM.ps1" >> "C:\TEMP\TEST_REMOTE.txt" } Invoke-Command -ComputerName $machine -ScriptBlock $script
0赞 Seth 8/30/2021
我不确定是否支持远程显示 GUI。您是否尝试过远程运行更新逻辑并在本地运行 GUI?这可能需要相当多的返工,但可能会得到你想要的结果。

答: 暂无答案