Powershell WFP Objects added to SyncHash are not passed to different runspaces - wpf

I am working on a project, this project is based on WPF GUI Wizard. The main idea of the Tool is that it will ask the user to input some data and at the same time perform checks on the provided data. Then after the user input all required data in all wizard pages, the tool will then call subscripts to perform its functionality. Well, WPF cause hangs and unresponsive PowerShell and to overcome this you need to use run spaces. So what I am doing is that I am opening a runspace that the GUI will run in it, then with the wizard, whenever the user provides an input, I validate this input in another runspace.
My problem is that whenever the user provides input, in the GUI runspace I can see the user input but when I call the other runspace I can still see the WPF object but the input provided in this object is not available.
To explain it further Below is a screenshot of the first input box in the GUI and for example, I have input something like (somqfqdn.anything) then I click submit. the GUI itself is running in a runspace called GuiRunspace, once the submit button is clicked I create another runspace called MPSB1Runspace and perform 2 checks (input is not empty, FQDN provided is resolvable).
If I went to the Runspace Debug, in the GuiRunspace if I checked the Inputbox Text I can see the input (somqfqdn.anything) but when I go to the MPSB1Runspace and check the Inputbox Text, I find it empty.
Powershell Runspace Debugging is as follow:
PS C:\Users\Administrator> Debug-Runspace Runspace32
Debugging Runspace: Runspace32
To end the debugging session type the 'Detach' command at the debugger prompt, or type 'Ctrl+C' otherwise.
Stopped at: $MPSB1Runspace = [runspacefactory]::CreateRunspace()
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>> $GuiHash.WizardMainPageInputBox1.Text
somqfqdn.anything
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
Stopped at: $MPSB1PSSesion = [powershell]::Create()
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
Stopped at: $MPSB1PSSesion.runspace = $MPSB1Runspace
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
Stopped at: $MPSB1Runspace.Open()
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
Stopped at: $MPSB1Runspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
Stopped at: [void]$MPSB1PSSesion.AddScript({
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
Stopped at: })
[DBG]: [Process:5900]: [Runspace32]: PS C:\Users\Administrator>>
PS C:\Users\Administrator> Debug-Runspace Runspace34
Debugging Runspace: Runspace34
To end the debugging session type the 'Detach' command at the debugger prompt, or type 'Ctrl+C' otherwise.
Stopped at: If ($GuiHash.WizardMainPageInputBox1.Text.Length -Eq 0) {
[DBG]: [Process:5900]: [Runspace34]: PS C:\Users\Administrator>> $GuiHash.WizardMainPageInputBox1.Text
[DBG]: [Process:5900]: [Runspace34]: PS C:\Users\Administrator>> $Global:GuiHash.WizardMainPageInputBox1.Text
Also, I have added a line of code in the MPSB1Runspace to disable a different submit button, but this action is not performed which means that the MPSB1Runspace do not have access to the SyncHash however, i have added the SyncHash to the MPSB1Runspace using the SessionStateProxy.SetVariable.
My Code is as follow:
# Create an Array that will hold all the XAML pages variables.
$XamlFilesArray = #($WizardMainWindowXaml, $WizardMainPageXaml, $WizardVCPageXaml, $WizardHostingVCPageXaml, $WizardControllerPageXaml, $WizardPrimaryNsxPageXaml, $WizardPrimaryVCPageXaml, $WizardFinalPageXaml)
# Create Sync HashTable (GuiHash) to allow readability across different Runscpases and add required variables.
$Global:GuiHash = [hashtable]::Synchronized(#{ })
# Crate the Runspace that will be used for the GUI
$GuiRunspace =[runspacefactory]::CreateRunspace()
$GuiRunspace.ApartmentState = "STA"
$GuiRunspace.ThreadOptions = "ReuseThread"
$GuiRunspace.Open()
$GuiRunspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)
# Create a PowerShell Session and add it to the Runspace.
$GuiPSSession = [PowerShell]::Create()
$GuiPSSession.Runspace = $GuiRunspace
# Create the GUI PowerShell Session ScriptBlock.
[void]$GuiPSSession.AddScript({
####Some the rest of the code that will build the GUI and load XAML Files
# Configure WizardMainPageSubmitButton1
$GuiHash.WizardMainPageSubmitButton1.Add_Click({
# Create new Runspace for this task.
$MPSB1Runspace = [runspacefactory]::CreateRunspace()
$MPSB1PSSesion = [powershell]::Create()
$MPSB1PSSesion.runspace = $MPSB1Runspace
$MPSB1Runspace.Open()
$MPSB1Runspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)
[void]$MPSB1PSSesion.AddScript({
If ($GuiHash.WizardMainPageInputBox1.Text.Length -Eq 0) {
$GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "Red"}) # Make Sure Printing Color is Red.
$GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided Data is empty, please provide NSX FQDN."}) # Print Error
} Else {
# Check if the input FQDN from WizardMainPageInputBox1 is resolvable and if not print error
If (!(Resolve-DnsName -Name $GuiHash.WizardMainPageInputBox1.Text.Text -ErrorAction SilentlyContinue)) {
$GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "Red"}) # Make Sure Printing Color is Red.
$GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided NSX FQDN is not resolvable. Please try again."}) # Print Error
} Else {
# Print Success, enable WizardMainPageInputBox2
$GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Foreground= "White"}) # Make Sure Printing Color is White.
$GuiHash.WizardMainPageErrorMessage.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageErrorMessage.Text = "Provided NSX FQDN confirmed. Please provide credentials."}) # Print Message
$GuiHash.WizardMainPageInputBox2.Dispatcher.Invoke([action]{$GuiHash.WizardMainPageInputBox2.IsEnabled= "True"}) # Enable WizardMainPageInputBox2 to continue
}
}
}).BeginInvoke()
}).BeginInvoke()
# Show Wizard Window.
$Global:GuiHash.WizardMainWindow.ShowDialog() | Out-Null
}).BeginInvoke()
$ShowGui = $GuiPSSession.BeginInvoke()
With the above code and the input of somefqdn.anything, I should see an error saying Provided NSX FQDN is not resolvable. Please try again.
Thank you for your help.

After some tests, I was able to work around this issue. when I am calling the second runspace, I have passed the content of the text box in a different variable and added it to the second reunspace setvariable
Code as below:
$MPSB1Runspace = [runspacefactory]::CreateRunspace()
$MPSB1PSSesion = [powershell]::Create()
$MPSB1PSSesion.runspace = $MPSB1Runspace
$MPSB1Runspace.Open()
$MPSB1Runspace.SessionStateProxy.SetVariable("GuiHash",$Global:GuiHash)
$MPSB1Runspace.SessionStateProxy.SetVariable("NsxFqdn",$Global:GuiHash.WizardMainPageInputBox1.Text)
[void]$MPSB1PSSesion.AddScript({
your code goes here and now $NsxFqdn have the input value
})

Related

How can I use the previous return to determine if I can send the alert by Powerhsell?

I'm going to use Dbatools to check my job is running or not. If it isn't running I need to send out an email alert.
I only have a few backgrounds with PowerShell programming.
# Import-Module D:\Tools\dbatools\dbatools.psd1 if it isn't loaded
If ( ! (Get-module dbatools )) {
Import-Module D:\Tools\dbatools\dbatools.psd1
}
# Get the job status
Get-DbaAgentJob -SqlInstance My_SQL_Instance -Job My_Job_Name | Out-File C:\DBA\Result.txt
# Send the email alert if the job is not running
Send-MailMessage -From My_Email_Address -Subject "My_Job_Name job is not running..." -To User_Email_Address -Attachments C:\DBA\Result.txt -Body "The MiantoEDW replication job is not running..." -BodyAsHtml -SmtpServer My_SmtpServer
I need to verify the property of CurrentRunStatus to determine to send an email alert or not.
I would do something like the following:
$jobStatus = Get-DbaAgentJob -SqlInstance My_SQL_Instance -Job My_Job_Name
$jobStatus | Select-Object Name,CurrentRunStatus | Export-Csv C:\DBA\Result.csv -NoTypeInformation
if ($jobStatus.CurrentRunStatus -ne "Executing") {
# Run some code if job is not running
Send-MailMessage -From My_Email_Address -Subject "My_Job_Name job is not running..." -To User_Email_Address -Attachments C:\DBA\Result.csv -Body "The MiantoEDW replication job is not running..." -BodyAsHtml -SmtpServer My_SmtpServer
}
else {
# Run some code if job is running
}
Get-DbaAgentJob doesn't display the CurrentRunStatus property by default. You will need to retrieve it, which is done by Select-Object CurrentRunStatus. Since the command outputs an object, I chose to use Export-Csv to export a cleaner output that aligns the object properties and values. $jobStatus stores the output of the Get-DbaAgentJob command. Accessing the $jobStatus.CurrentRunStatus property for value Executing will verify if a job is currently running.
I've not used dbatools but I assume the CurrentRunStatus is available in the Result.txt file you're outputting to?
If so, assign the result of Get-DbaAgentJob to a variable and then Out-File from that variable. Then access the CurrentRunStatus property from the variable to determine whether or not to send the alert.

AD users getting locked out every 20 seconds

I have been searching high and low for an answer, but I cannot seem to figure out why a few of our users keep getting locked out every 30 seconds. I unlock the account and then can watch the login attempts within seconds lock them out. I have tried tools like account lockout status and Netwrix, and I cannot find out what computer/service/task that is causing it. I did turn on netlogon logging, but it doesn't tell me which computer its coming from and it also doesn't say in the event viewer logs. Any help would be greatly appreciated!!!
I have put an example event, and netlogon line below:
Netlogon:
01/04 11:51:07 [LOGON] [20280] DOMAIN: SamLogon: Transitive Network logon of (null)\John Jones from (via WEB-SERVER) Returns 0xC000006A (there is nothing after from)
Event:
Failure Information:
Failure Reason: Unknown user name or bad password.
Status: 0xC000006D
Sub Status: 0xC0000064
Process Information:
Caller Process ID: 0x0
Caller Process Name: -
Network Information:
Workstation Name:
Source Network Address: -
Source Port: -
Do you use LDAP integrated applications?
Advise those end users to clear browser cache (if not already) - if Windows users, clear credentials in:
Credential Manager->Windows Credentials->Delete all entries under "Generic Credentials"
Does your organisation authenticate users who connect to corporate WiFi using AD? If so check that the end users mobiles/tablet devices have been configured with the new password, best way to do this is to forget the connection and re connect using new credentials.
We've had very similar issues in the past and resolved doing the above.
I have recently done this for myself.
The script can show you the timestamp, username, machine name where the lockout event is being originated.
Here is code:
# Set default parameters and variables
param (
[string]$DomainName = $env:USERDOMAIN,
[string]$UserName = "*",
[datetime]$StartTime = (Get-Date).AddDays(-3)
)
# check if current powershell version is 4 or higher
if ($Host.Version.Major -lt "4") {
Write-Host "`n`nError: You need at least version 4 PowerShell for logging to work, `nCurrent version:"$Host.Version.Major -BackgroundColor Red -ForegroundColor white
Write-Host "`nBefore you start using this script, please upgrade your PowerShell from Microsoft website!" -BackgroundColor Yellow -ForegroundColor Black
Read-Host "`n`nScript execution finished, press enter to exit!"
Exit
}
# Grab the information about your AD forest
$Forest = [system.directoryservices.activedirectory.Forest]::GetCurrentForest()
# Get list of all domain controllers in the forest
$DC = $Forest.domains | ForEach-Object {$_.DomainControllers} | ForEach-Object {$_.Name}
# Prompt user to enter a pacific username or accept default (which means look for all locked out events)
Write-Host "`n`nEnter a UserName to search user specific locked out events `n`nOR `n`nPress enter to search all locked out usernames!" -BackgroundColor Yellow -ForegroundColor Black
sleep 3
$TestName = Read-Host "`nPlease enter a UserName or Press enter"
if ($TestName -ne $null -and $TestName) {[string]$UserName = $TestName}
Write-Host "`nScript will search for locked out events on the following domain controllers..." -BackgroundColor Gray -ForegroundColor Black
$dc
# Search for locked out event of each DC and store them in variable
$dc | foreach {
Write-Host "`nChecking for locked out events on $_, please wait..." -BackgroundColor Gray -ForegroundColor Black
$OutPut = Invoke-Command ($_) {
$ErrorActionPreference = "SilentlyContinue"
Get-WinEvent -FilterHashtable #{LogName='Security';Id=4740;StartTime=$Using:StartTime} |
Where-Object {$_.Properties[0].Value -like "$Using:UserName"} |
Select-Object -Property TimeCreated,
#{Label='UserName';Expression={$_.Properties[0].Value}},
#{Label='ClientName';Expression={$_.Properties[1].Value}}
$ErrorActionPreference = "Continue"
} | Select-Object -Property TimeCreated, 'UserName', 'ClientName' |Out-Host
if ($OutPut -eq $null -and !$OutPut) {Write-Host "`nWarning: No lockout events were found!`nContinuing the search..." -BackgroundColor Yellow -ForegroundColor Black}
else {$OutPut}
}

How to run a scheduled task to stop and start SSRS service with elevated permissions?

I have this SSRS latency issues on my site. So I have googled it and found out that it is the common issues for so many people. Here it is:
I have created a powershell script as follows:
Stop-Service "SQL Server Reporting Services (MSSQLSERVER)"
Start-Service "SQL Server Reporting Services (MSSQLSERVER)"
$wc = New-Object system.net.webClient
$cred = [System.Net.CredentialCache]::DefaultNetworkCredentials
$wc.Credentials = $cred
$src = $wc.DownloadString("http://example.com/Reports/Pages/Folder.aspx")
When i run this script from poweshell cmd it is throwing me an error says cannot open/access sql report server service. It seems like permissions issue. Then I came with this online solution, which invokes/elevates admin permissions to run the script to that perticular user.
function Invoke-Admin() {
param ( [string]$program = $(throw "Please specify a program" ),
[string]$argumentString = "",
[switch]$waitForExit )
$psi = new-object "Diagnostics.ProcessStartInfo"
$psi.FileName = $program
$psi.Arguments = $argumentString
$psi.Verb = "runas"
$proc = [Diagnostics.Process]::Start($psi)
if ( $waitForExit ) {
$proc.WaitForExit();
}
}
But I dont know how to run this function before running that script. Please suggest. I have added this function also to the same script file and added function-Admin() call at the top of the script to to execute this function before running the script as follows:
function-Admin()
Stop-Service "SQL Server Reporting Services (MSSQLSERVER)"
Start-Service "SQL Server Reporting Services (MSSQLSERVER)"
$wc = New-Object system.net.webClient
$cred = [System.Net.CredentialCache]::DefaultNetworkCredentials
$wc.Credentials = $cred
$src = $wc.DownloadString("http://example.com/Reports/Pages/Folder.aspx")
But is throwing following error:
Please specify a program
At C:\SSRS_Script\SSRSScript.ps1:3 char:39
+ param ( [string]$program = $(throw <<<< "Please specify a program" ),
+ CategoryInfo : OperationStopped: (Please specify a program:String) [], RuntimeException
+ FullyQualifiedErrorId : Please specify a program
You are getting that error because the function Invoke-Admin() was designed to have parameters passed for the program you wanted to run with elevated privledges. If you want your powershell script SSRSScript.ps1 to use this Invoke-Admin() you could convert it to a standalone script.
Take the code without the function declartion and outer brackets. Save this a file called Invoke-Admin.ps1
param ( [string]$program = $(throw "Please specify a program" ),
[string]$argumentString = "",
[switch]$waitForExit )
$psi = new-object "Diagnostics.ProcessStartInfo"
$psi.FileName = $program
$psi.Arguments = $argumentString
$psi.Verb = "runas"
$proc = [Diagnostics.Process]::Start($psi)
if ( $waitForExit ) {
$proc.WaitForExit();
}
With that created then you could try to elevate your script with the following:
C:\*pathtoscript*\Invoke-Admin.ps1 -program "Powershell.exe" -argumentString "-file C:\SSRS_Script\SSRSScript.ps1"
You should get the elevation prompt at that point and then, once accepted, will run another window with your script using admin rights.
This is by no means the only way to accomplish this goal.
Scheduler
You have this in the title but dont really cover it in the question. Running this as a scheduled task will not work since it requires user input. You could however just make a task with your script as is assuming it works unattended.
General Tab
Run whether user is logged on or not
Run with highest privileges
Action > New...
Action: Start a program Program/script: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
Add arguments: -ExecutionPolicy Unrestricted -NoProfile -File C:\SSRS_Script\SSRSScript.ps1
Start in (optional): %SystemRoot%\system32\WindowsPowerShell\v1.0

Release Management 12 - Create Web Site with Host Header

Is there a way to create a web site with Release Management v12 that will include a host header option?
My goal is to be able to host multiple sites on a single server, all binding to port 80 with different host headers. i.e. http://project1.development.local/, http://project2.development.local/
I'm able to create a web site with a host header from the AppCmd.exe, yet this requires an administration rights. Thought about using powershell, yet a UAC prompt will be triggered.
For right now, I'm having to manually create the server's web site to include the host header and I'd like to have a totally automated release process.
TIA!
There's nothing in-the-box for it, but as luck would have it, I've hacked something together to handle site bindings:
param(
$SiteName=$(throw "Site Name must be entered"),
$HostHeader,
$IpAddress,
$Port,
$RemoveDefault=$(throw "You must specify true or false")
)
Import-Module WebAdministration
try {
$bindingExists = (Get-WebBinding "$SiteName" -Port "$Port" -Protocol "http" -HostHeader "$HostHeader" -IPAddress "$IpAddress")
if (!$bindingExists) {
Write-host "Creating binding for $SiteName : Host header $HostHeader and IP Address $IpAddress"
New-WebBinding "$SiteName" -Port $Port -Protocol "http" -HostHeader "$HostHeader" -IPAddress "$IpAddress"
}
else {
Write-host "Site $SiteName already has binding for host header $HostHeader and IP Address $IpAddress"
}
if ($RemoveDefault -eq "true") {
$defaultBinding = Get-WebBinding "$SiteName" | where {$_.bindingInformation -eq "*:80:" }
if ($defaultBinding -ne $null) {
Write-Host "Default binding exists... removing."
$defaultBinding | Remove-WebBinding
}
else {
Write-Host "Default binding does not exist"
}
}
}
catch {
Write-host $_
exit 1
}
exit 0
You can create a custom tool in RM to leverage this script, just pass it the parameters specified in the param block.
You should never have to use AppCmd.exe... If the built-in tools don't meet your needs, the WebAdministration PowerShell module should be able to do everything else.

CakePHP 2.2 AclExtras aco_sync in browser (sh permission denied)

I'm working on a remote server and I can't use the console because ssh is not enabled. So I need to run aco_sync directly from the browser (or any other way that doesn't involve the shell).
I managed to sync acos on my local dev server with the following code in controller/action:
$command = ROOT . DS . APP_DIR . DS . 'Console' . DS . 'cake';
$params = ' -app ' . ROOT . DS . APP_DIR;
$params .= ' AclExtras.AclExtras';
$params .= ' aco_sync';
$result = shell_exec($command . $params);
But on the production server (with cPanel) I just get no response for about 5 minutes and then I get an internal server error (500). I simply hangs. Actually, this happened on two different VPS servers with cPanel. In the first one, I had ssh and was able to run the command from the console. But when running the quoted code from the browser, I hung just as the other server.
I found no logged errors either on php log files nor cake's log files.
The action is prefixed with "admin_" and ACL doesn't allow execution if not logged in.
'./cake' script file has execute permissions (took me a while to figure this was necessary).
I tried on Chrome and IE8.
Debug level was set to 1.
After trying to run the script, the page broke and I wasn't able to browse until I opened an incognito window or restarted the browser.
I think the server's memory gets completely consumed when I run this script. I've had to restart httpd to get the site up and running again on the server that I could control.
I've seen some implementations using $dispatcher->dispatch() and tried a bunch of them but with no luck.
Any ideas?
App::uses('ShellDispatcher', 'Console');
$command = '-app '.APP.' AclExtras.AclExtras aco_sync';
$args = explode(' ', $command);
$dispatcher = new ShellDispatcher($args, false);
if($dispatcher->dispatch()) {
echo 'OK';
} else {
echo 'Error';
}
Try this, the $dispatcher->dispatch(); seems to show something only in case of an error.
run this and check your database.
App::uses('ShellDispatcher', 'Console');
$command = '-app '.APP.' AclExtras.AclExtras aco_sync';
$args = explode(' ', $command);
$dispatcher = new ShellDispatcher($args, false);
try {
$dispatcher->dispatch();
} catch (Exception $e) {
pr($e);
}

Resources