Friday, October 20, 2017

Powershell Scripting Environments, Part I


Earlier this year, I said I would give some information regarding some of the many scripting tools you can use for creating Powershell scripts.  Here are just a couple of those tools that I currently use or have used in order to create my scripts:

 

1. PS Shell
This is equivalent to the Command Prompt.  When the shell is started, you will see PS C:\
 
 

           
  You can initialize variables within the shell.  Let's set the variable $messsage to 'This is a test'
 



We can see what is in the variable by running $message

The variable and contents are keep in memory and can be used with further cmdlets.
 
The drawback, for me, is that making changes involves either typing in a command again, or using the arrow keys to bring back a command you ran.  It may not be a problem if there are only a couple of lines to the script.  But, if you want to create a script with a lot of code, you going to want to use an integrated scripting tool.
 
 
2. Integrated Scripting Environment (ISE)
The ISE is provided by the Windows OS.  You can start the ISE by typing ISE in the Powershell shell
 
 
 
The ISE will appear
 
This environment allows you to create and run a script in the right panel.  When you run the script the output will appear in the left panel.
 
Here are a couple of tool bar items you should know how to use:
 Click this if you want to run the entire script.  The keyboard equivolent is F5
 
 
This allows you to run a specific line or group of lines in the script.  For example
By clicking on the
 
You will only run the $users line of the code.  You can then check what is in the $users variable by typing $users in the left panel.
 
 
 
 
This is equivolent to CLS, it clears the output panel.
 
I like using the ISE because a) it comes with Windows, and b) it allows you to create, update, and run individual lines of a script.
 
I hope you find this information helpful.  Next week, I will show you some popular free or pay tools that add some additional functionality to the scripting environment.



Monday, October 9, 2017

Adding Security to Invoke-Command Script


Last week, I posted a script to gather user information from a different domain.  In that script the -Credential parameter was set to a specific account name.  When running the script, a prompt would ask for the password.  Although it worked it isn't the most secure way of getting the information. 

This week, let's add some additional security and eliminate the need for any additional information. 

First, you need a way to store an encrypted password.  The following script will do just that:

$credfilepath = "c:\scripts\password_file.txt"
$cred = read-host -AsSecureString "`nPlease enter the new password "
$cred | ConvertFrom-SecureString | Set-Content $credfilepath 

The first line sets the $credfilepath variable to where you want the credential file to reside.

The second line is what will prompt you for the password of the account you will be using to run the Get-ADUser statement in the main script.

The third line reads the $cred variable, converts the $cred information from a secured string to an encrypted string, and stores the information in the file assigned to the $credfilepath variable. 

Once you have the password in an encrypted format, we can make the following changes to the original script:  

$pwd = get-content C:\scripts\password_file.txt | ConvertTo-SecureString
$EXTUser = '<domain>\<user name.'
$cred = New-Object System.Management.Automation.PSCredential $EXTUser, $pwd
invoke-command -ComputerName server1.mydomain.net -Credential $cred -ScriptBlock { get-aduser -filter * -Properties * -SearchBase 'OU=Titles,DC=MyDomain,DC=Net' | Select-Object DisplayName,sAMAccountName,ObjectSid | FL } 

The first line variable converts the encrypted information in password_file.txt to a secured string.

The second line variable holds the account that has permissions to run the script.

The third line variable gets the credential information using the System.Management.Automation.PSCredential class.

Change the -Credential value, in the Invoke-Command line, to -Credential $Cred. 

Now, when you run the script, you will not be prompted for a password. 

I use this type of security method a lot at my real job.  In my opinion, it is a easy way to add a level of security to scripts. 

Please let me know if you have any questions about this script.

Monday, October 2, 2017

Using Invoke-Command on a Remote Domain Server

Greetings everybody!

Sorry for the long delay.  I was busy fishing and visiting family.  Now that summer is over I have some great stuff to post regarding things I have learned with PowerShell.

Just last week I was asked to get a list of user information from one of our external domains.  The easy path would have been to RDP to the remote domain controller and run a PS script.  However, I try to make my scripts usable by other people who don't, necessarily, have the same permissions as myself.

For me, the easiest way is to use Invoke-Command...here is the script:
invoke-command -ComputerName <FQDN> -Credential <domain\username> -ScriptBlock { get-aduser -filter * -Properties * -SearchBase 'OU=People,DC=MyDomain,DC=Net' | Select-Object DisplayName,sAMAccountName,ObjectSid | FL }

The -ComputerName must use the fully qualified domain name (i.e., tstserver.mydomain.net).

The -Credential must be an account that has sufficient permissions to run the script on the remote server.  For example, Mydomain\Administrator

You can narrow down your search by specifying the -SearchBase.  This helps keep out any clutter from Active Directory.

The output will look like this:
DisplayName          : Bob Johnson
sAMAccountName : bJohnson
ObjectSID:              : S-1-1-11-11111111-1111111111111-11111111111-1111

Next week: I will show how to use encrypted variables so you don't have to enter in a password.

Monday, May 1, 2017

Creating Graphs Using PowerShell

I'm back!

Full disclosure...I have been doing a lot of fishing with my friends and spending time with family.  This was necessary because I was getting crabby for no reason.  I'm feeling much better thanks, again, to my friends and family members.

Now, on to graphing...

I subscribe to the PowerShell Power Users group on LinkedIn.  Looking at the latest articles, I found an article by Kevin Marquette called "Graph All Things! with PSGraph and GraphViz"  (https://www.linkedin.com/groups/140856/140856-6232213168123453443).  This is pretty cool.

NOTE: using PSGraph is not like graphing in Excel.  This are simple graphs that can be used for some complex solutions.  For example, here is a simple graph:

Basic Graph
graph basic {
    edge -From start -To middle
    edge -From middle -To end
}
Here is a sample of a complex graph:

}  | Export-PSGraph -ShowGraph
Source
graph finite_state_machine @{rankdir='LR';size=8.5} {
    node  LR_0,LR_3,LR_4,LR_8 @{shape='doublecircle'}
    node @{shape = 'circle'}
    edge LR_0 LR_2 @{ label = "SS(B)" }
    edge LR_0 LR_1 @{ label = "SS(S)" }
    edge LR_1 LR_3 @{ label = 'S($end)' }
    edge LR_2 LR_6 @{ label = "SS(b)" }
    edge LR_2 LR_5 @{ label = "SS(a)" }
    edge LR_2 LR_4 @{ label = "S(A)" }
    edge LR_5 LR_7 @{ label = "S(b)" }
    edge LR_5 LR_5 @{ label = "S(a)" }
    edge LR_6 LR_6 @{ label = "S(b)" }
    edge LR_6 LR_5 @{ label = "S(a)" }
    edge LR_7 LR_8 @{ label = "S(b)" }
    edge LR_7 LR_5 @{ label = "S(a)" }
    edge LR_8 LR_6 @{ label = "S(b)" }
    edge LR_8 LR_5 @{ label = "S(a)" }
}  | Export-PSGraph -ShowGraph

I can use PSGraph to give high level views of how some of our processes are working.  I can see using this for network diagrams and flow charting.

My next post will be on different scripting environments (ISE, ISESteroids, Powershell Plus, etc.)  Stay tuned.

Friday, April 28, 2017

Sorry for the delay...

I have been working on other projects that has used up my free time.  I do have an article coming up regarding the use of PSGraph.  It will be out next week.

Mike

Wednesday, March 29, 2017

Powershell Menu Script

While I was in my SAFe Practitioner class, an idea just popped into my head.  I should create a menu-type script that allows me to display all the administrative scripts I created.  This would give me quick access to my scripts without have to continually find the script, load the script, and run the script.

So...new project.  A convenient, and cool looking, menu of scripts.  I will start on this tomorrow.  I still have email I have to get through.

Tuesday, March 28, 2017

Off This Week

I am in SAFe Agile 4.0 training this week.  I'll have something new next week.

Friday, March 24, 2017

SQL Instance/Database Enumeration Script Version 1.0

IT IS ALIVE...

Through weeks of hard work I have created the following scripts that will get a list of SQL servers\instances, and will list out the databases for each server\instance.  Please forgive the code formatting.  The cut and paste to the blog page is wonky.

Get-instancesCMDLET.ps1
import-module activedirectory

$names = get-adcomputer -Filter * -Properties * -SearchBase '<LDAP base>' -ResultPageSize 1000 | where-object {$_.Name -NOTLIKE '*clus*'}

foreach($Name in $names) {

$result = Test-Connection -ComputerName $Name.name -Quiet # checks if the server is online

if ($result) {
 $objReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Name.name)

$objRegKey= $objReg.OpenSubKey("SOFTWARE\\MICROSOFT\\MICROSOFT SQL SERVER" )

if ($objRegKey -ne $null) {

$instances = $objRegKey.GetValue("InstalledInstances", $null)


if ($instances.Count -gt 0) {

foreach($i in $instances) {

if ($i -match 'MSSQLSERVER') {

$output = $Name.name

} Else {

$output = $Name.name + '\' + $i




 
} $output | out-file -Append server_instance.csv

} #end of $instances foreach




 
} # end of if $instances.count

} # end of if $objRegKey

} # end of if $results

} # end of $names foreach 


The -Searchbase should be the OU in which you search for the servers, i.e., OU=Server,DC=abc,DC=com
Make sure the server_instances.csv file is deleted before you run the script so you don't have a file of redundant data.

Get-SQLServerInstanceDatabase.ps1 
function Get-DBList ($server)



{
 
$srv = New-Object 'Microsoft.SqlServer.Management.Smo.Server' $server # creates SMO object for server

$srv.Databases | Select name # returns database name(s)

 } #end Get-DBList function




 
 

$dbservers = import-csv server_instance.csv # this loads the SQL servers and instances created in the Get-InstancesCMDLET.ps1 script

$dbexclude = 'tempdb','model','msdb','master','dbmaint' # these are tables that every SQL server creates

foreach ($dbserver in $dbservers) {

$dbs = Get-DBList $dbserver.DBInstance # puts server name and instance in the variable

foreach ($db in $dbs) {

if ($db.name -notin $dbexclude) {

$hold = $dbserver.dbinstance + ',' + $db.Name

$hold | out-file -Append fullinstanceDB.txt

} # end if

} # end of $dbs foreach

} # end of $dbservers foreach



 

Again, make sure the server_instances.csv file is deleted before you run the script so you don't have a file of redundant data.