Search code examples
wpfpowershellstart-job

Restart-computer command in start-job scriptblock always returns as state “blocked”


If I run the code below then the created job “test3” always has a state “blocked”. It never executes. It has no additional error message. When I run the command in the start-job scriptblock separately, then it does work (restart-computer -computername $computer -credential $MySecureCreds -force).

[void] 
[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="CSS Server Reboot" Height="450" Width="800">
<Grid>
    <ComboBox Name="Server_Combobox" SelectedValuePath="Content" 
HorizontalAlignment="Left" Margin="240,107,0,0" VerticalAlignment="Top" 
Width="120">
         <ComboBoxItem Name="Server1">10.15.12.148</ComboBoxItem>          
    </ComboBox>
    <Label Name="Title_Label" Content="CSS – Server Reboot&#xD;&#xA;" 
HorizontalAlignment="Left" Margin="240,41,0,0" VerticalAlignment="Top" 
Height="34" Width="284" FontSize="16"/>
    <Button Name="Reboot_Button" Content="Reboot" HorizontalAlignment="Left" 
Margin="449,107,0,0" VerticalAlignment="Top" Width="75"/>
    <TextBox Name="Reboot_Textbox" Grid.Column="1" HorizontalAlignment="Left" 
Height="173" Margin="81,180,0,0" TextWrapping="Wrap" 
VerticalScrollBarVisibility="Auto" Text="" VerticalAlignment="Top" 
Width="294"/>
</Grid>
</Window>

"@
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}

# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name 
($_.Name) -Value $Form.FindName($_.Name)}


# Secure credential creation
$Username = "XXX"
$Password = "XXX"
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$SecureString = $pass
$MySecureCreds = New-Object -TypeName 
System.Management.Automation.PSCredential -ArgumentList $Username,$pass 

# Use the combobox
$computer
$jobtest
$timer = new-object System.Windows.Threading.DispatcherTimer


$Server_Combobox.add_SelectionChanged( { 

param($sender, $args)

$Script:computer = $sender.SelectedItem.Content

} )



#Assign reboot event to button
$Reboot_Button.Add_Click({

$sb = [scriptblock]::Create("restart-computer -computername $computer -
 credential $MySecureCreds -force")
Start-Job -Name "test3" -ScriptBlock $sb 

$Script:jobtest = Get-Job -Name "test3"

$Reboot_Textbox.AddText("The restart procedure is starting.`n")

$timer.Interval = [TimeSpan]"0:0:5.00"


$timer.add_Tick({

if($jobtest.State -ne "Running"){
$Reboot_Textbox.AddText("The restart failed, please contact IT Ops !!!`n")
$Reboot_Textbox.AddText("The error message is:`n")
$Reboot_Textbox.AddText($jobtest.ChildJobs[0].JobStateInfo.State)
$Reboot_Textbox.AddText("`n")
$Reboot_Textbox.AddText($jobtest.ChildJobs[0].JobStateInfo)
$Reboot_Textbox.AddText("`n")
$Reboot_Textbox.AddText($jobtest.ChildJobs[0].Error)
$Script:timer.Stop()
}elseif($jobtest.State -eq "Completed"){
$Reboot_Textbox.AddText("The restart procedure completed successfully.")
$Script:timer.Stop()
Wait-Job -Name test3 | Remove-Job
}else{
$Reboot_Textbox.AddText("The restart procedure is ")
$Reboot_Textbox.AddText($jobtest.State)
$Reboot_Textbox.AddText("`n")
}         

})

$timer.Start()

})

$Form.ShowDialog() | out-null

Does anyone have any idea how to solve this? Does it have to do with the “credential” option in the scriptblock?


Solution

  • Change this:

    $sb = [scriptblock]::Create("restart-computer -computername $computer -credential $MySecureCreds -force")
    

    To this:

    $sb = { restart-computer -computername $Using:computer -credential $Using:MySecureCreds -force }
    

    You need the Using: scope modifier so that the current value gets injected into the scriptblock.

    When you do it the first way, using double-quoted strings, the variables get put inside the string before the scriptblock is created.

    You end up with something like:

    $sb = { restart-computer -computername WhateverIsInComputer -credential System.Management.Automation.PSCredential -force }
    

    Which won't work.