-
Debug a PowerShell script running in PowerShell console locally or remote after it has started
5 April, 2017 PowerShellAlways wanted to debug a running PowerShell script in a console which looks like it's stuck on something. Now you can in PowerShell 5.0 with the following steps.
- First find the process id of the running script in the taskmanager details tab (PID).
- Now start PowerShell ISE and activate the console (Ctrl-D)
- Enter Enter-PSHostProcess -id yourid
- Enter Debug-Runspace -id 1 (most of the time it's Runspace 1)
PowerShell ISE will now load the script and show it halted at the currently executed statement. Now you can run it again after inspection or continue debugging it and/or set breakpoints.
To test this scenario create a long running script like this
Write-Host "Long running script with PID: $pid" while ($true) { sleep -Seconds 1 Write-Host "In next cycle" }
Start this script in a PowerShell console and start PowerShell ISE with the following commands
Enter-PSHostProcess -id 14468 # enter here your script pid Debug-Runspace -id 1
If your script is running on another machine and PowerShell remoting is configured you can also do this with remote scripts. Before using Enter-PSHostProcess open a session with Enter-PSSession -ComputerName
and follow the same steps. If you want more details about this functionality lookup the following commands on Microsofts site.
Enter-PSHostProcess, Get-Runspace, Debug-Runspace, Enable-RunspaceDebug -BreakAll, Wait-Debugger, Enter-PSSession
The implementation of PowerShell runspaces gives us a lot of flexibility and allows for some crazy scenarios. Say I want to run a script and let it break at some point with the Wait-Debugger statement and continue debugging with PowerShell ISE. When I add the Wait-Debugger statement the PowerShell console running the script breaks at the statement in the cmd-line debugger of PowerShell. Thats not what I want, I want PowerShell ISE. You can work-around this by using a helper script which executes your script.
[CmdletBinding()] Param( [alias('f')] [string] $aFile = "$PSScriptRoot\long-running.ps1" ) Set-StrictMode -Version Latest Set-Location $PSScriptRoot echo "Debug Script" echo "" echo "Parameters" echo " File: $aFile" echo "" echo "Computer details" echo " Computer: $($env:ComputerName)" echo " WhoAmI: $(WhoAmI)" echo " PowerShell: $($psversiontable.PsVersion)" echo " .Net: $($psversiontable.ClrVersion)" echo "Currentfolder: $(get-location)" echo "" $rs = [System.Management.Automation.RunspaceMode]::NewRunspace $PowerShell = [PowerShell]::Create($rs) Write-Host "**** Script is running in debugging mode ****" Write-Host "" Write-Host "To start debugging execute the following commands in a PS-Console" Write-Host "" Write-Host "`t Enter-PSSession -ComputerName $($env:computername) -Credential 'yourcredentials'" Write-Host "`t Enter-PSHostProcess -id $pid" Write-Host "`t Debug-Runspace -id $($PowerShell.Runspace.Id)" Write-Host "" Write-Host "To end debugging, perform the 'Exit-PSHostProcess' in PS-Console after abort" [void]$PowerShell.AddScript(". '$aFile'") [void]$PowerShell.Invoke() Write-Host "Debugging session ended"
Add to your long-running script the Wait-Debugger or Enable-RunspaceDebug -BreakAll
Write-Host "Long running script with PID: $pid" while ($true) { sleep -Seconds 1 Enable-RunspaceDebug -BreakAll Write-Host "In next cycle" }
Executing the scenario mentioned at the beginning of the blog-post shows you that the script will break at the Enable-RunspaceDebug statement.
Comments -
Use secured MongoDb database with Masterkey or SA account in C#
When you have secured your MongoDb database with a masterkey how can you change your c# code with minumum effort?
First change your mongo-url or connection string to include the password. I assume you have stored this in your web/app.config.
Syntax for connection string is:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
Our sample url will be:
mongodb://admin:********@127.0.0.1/mydb?connect=automatic
Change your connection string accordingly.
Now change your code to use the password from the connection string to authenticate on the admin database. I assume you have read the connectionstring from the config file and created the MongoUrl or MongoClient somewhere in your code. Add MongoClientSettings after the creation of the MongoUrl and use the new MongoClientSettings to create the MongoClient. Modify the MongoClientSettings to authencicate on the admin database. In code this looks like:
var url = new MongoUrl(aConnectionstring); var mcs = MongoClientSettings.FromUrl(url); MongoCredential cred = mcs.Credentials.FirstOrDefault(); if (cred != null) { // reformat creds to use admin database and not current database // admin database contains the global database users if (cred.Evidence is PasswordEvidence) { var creds = new List<MongoCredential>(); creds.Add(MongoCredential.CreateCredential("admin", cred.Username, (cred.Evidence as PasswordEvidence).SecurePassword)); mcs.Credentials = creds; } } mcs.Freeze(); var mc = new MongoClient(mcs);
Now when you connect to your database/collection with the MongoClient it's always authenticated against the admin database on your MongoDbServer.
Comments -
Securing MongoDB with Masterkey or SA account
Since resent events an unsecured MongoDB Server in the open is not a good security practice and by default no system account or database user account is created when MongoDB is installed, you need to do it by yourself. It's not that difficult but another step to do.
I will go over the steps on a Windows installation of MongoDB. I assume you have installed MongoDB with the MSI Installer and run it as a Windows Service.
We are now going to create a MongoDB user which has full access to the MongoDB Server. This means all databases available on this server and databases that will be created in the future. Hence the database masterkey/system administrator paradigm.
Now start the mongo shell (mongo.exe from the program files folder) and enter the following statements
use admin
db.createUser( { user: "admin" , pwd: "**************", roles: ["userAdminAnyDatabase", "dbAdminAnyDatabase", "readWriteAnyDatabase"] } )
Now we need to re-start the MongoDB server but with security enforcement enabled by default. On Windows we can do this by editing the registry or changing the config file if used. I show you how to do this in the registry.
Start regedit.exe
Go to 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MongoDB'
Locate the 'Imagepath' key with '"C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe" --logpath "C:\data\logs\log.txt" --dbpath "C:\data\db" --service'
and change it into '"C:\Program Files\MongoDB\Server\3.4\bin\mongod.exe" --logpath "C:\data\logs\log.txt" --dbpath "C:\data\db" --service --auth'
Close the mongo shell
Restart the MongoDB in the Task Manager Services Tab
And reconnect with the mongo shell and authenticate
db.auth("admin", "***********")
You are now connected to a secure MongoDB server and when running this public users need to authenticate. To further strengthen security, it's advisable to create a more granular security access to your MongoDB Server/Databases by creating more users with lesser security roles. See for more details the MongoDB Manuals.
When running your server public it is also a good practise to use a ssl connection to your MongoDB server but this requires another post.
Comments