In my last post almost 6 months ago I spoke about PowerShell profiles, especially how I preferred a simple profile. If you are just doing some simple things that you need right away or aren’t administering an application like Azure, SharePoint or Office365 then you can suffice with the simple profile. Since I manage Office365 and the applications mentioned above I have morphed to a second profile that I now load to load everything that I need for those applications. The time entering my username and password for those accounts, saves on having to load a different PS1 or create a function to do it later. My thoughts about not creating the function is if I do it once the first time I can just continue working without stopping when I need to do something in those applications.
My previous profile looked like this:
$a = (Get-Host).PrivateData
$a.ErrorForegroundColor = “green”
Just your basic profile that sets my default location, and sets the color of the evil error message RED to easier to read GREEN on the blue background. Now for my work within all of the applications that I admin this is the profile I use:
$env:path += “;C:\PowerShell”
$host.ui.RawUI.WindowTitle = “Administrator – Sysadmin Mode”
$Shell = $Host.UI.RawUI
$a = (Get-Host).PrivateData
$a.ErrorForegroundColor = “green”
Import-Module ‘C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell’
$cred = Get-Credential
Connect-MsolService -Credential $cred
Connect-AzureAD -Credential $cred
Connect-SPOService -Url https://company-admin.sharepoint.com -Credential $cred
So, that is a lot more involved, but I only interact with the loading of the profile once at the line: $cred = Get-Credential, which is where I enter my credentials for Office365. Obviously our AzureAD is connected to Office365 which includes our SharePoint too so I only need to enter my credentials once.
First a disclaimer: I close this profile shell when I leave the computer even though I lock the computer screen. This is best practice so that if anyone gains access to my workstation, they do not gain access to my Sysadmin account in PowerShell to do damage. We change our passwords on a regular basis to prevent access as is also best practice, but anything you can do to lower a hackers attack surface the better.
So, what does this all do? Well that is a pretty good question.
- I set the default location of my console as my PowerShell folder that contains all my scripts.
- I add the PowerShell folder to the system path
- Change the title of the shell to let me know I am running in Sysadmin mode.
- Set the system shell as the current console
- Set the error color to green
- Import all the Modules I need to make sure they do get loaded, including the SharePoint Module that is an MSI install
- Store my credentials for this session for use logging in
- Connect to all the services using the credentials I supplied. The SharePoint SPOService would need you to replace the word “company” with your company name.
I believe that this front end work saves me a lot of time when I have to do something in SharePoint or the SAAS client or AzureAD.
Something that I have found useful in getting a hard copy of is a computers installed software, vendor and version. Today I’m just going to work with the local computer. In another post I will talk about the ability to get all software installed on a group of computers. In PowerShell there are a few ways to do what I am going to show you. The one I prefer is Get-CimInstance. I use this over Get-WMIObject becasue it gets me more information and Get-WMIObject is actually the older way from PS 2.0. It has really been replaced with Get-CimInstance. If you go to Introduction to CIM Cmdlets (MSDN Blog) you will find this quote:
“Getting/Enumerating instance of a class is the most commonly performed operation. We wanted the new Get-CimInstance Cmdlet to have better performance and even better user experience as compared to the old Get-WmiObject cmdlet. To achieve these goals we made the following design decisions:”
So, how do I write the code?
Gcim Win32_Product (gcim is the alias for Get-Ciminstance)
That just spits out the information in the ugly format below:
I like my data so I can read it properly and with all the data I really want. Lets add a Piped command:
| Format-Table name, version, vendor
This gives you the results below:
Okay, so that’s nice, but how about in a CSV file that I can print or look at later? Cool, lets do it:
Gcim Win32_Product | Select-Object name, version, vendor | Export-Csv C:\software1.csv
I know, your saying wait you changed the second line from Format-Table to Select-Object and you would be correct. Why did I change it, well format-Table is for output to the console, not for something you are piping to Export-CSV. You have to Select the Objects you want to send to the CSV file to get proper data. Go ahead and try to use the Format-Table once to see you get nothing you can use in the CSV file. The output you get when you use the Select-Object is below. That’s how I would like it, how about you?
This afternoon I updated a piece of software we use for instruction and classroom management on 37 servers. The software is actually a service, while its teacher and student versions are installed on the individual classroom machines via an auto update function within the service.
In a situation that many of us as Systems Administrators have been in, I would have normally did an RDP to each server, copied the service install, the teacher and student install to the server and ran the service MSI to install it. That would be on average 5 minutes on each server for a total time of just over 3 hours.
To avoid that we now have PowerShell and the Power of PowerShell. I wrote a script, tested it on a Dev server until I felt comfortable that is was debugged and then ran it on the production servers. The writing of the script took a half hour, testing a half hour and running it to completion from my desk in a PowerShell console took 4 minutes.
Yes, that’s 4 minutes to run the script to completion on all 37 servers. Add the writing and testing time and you get a total of one hour and four minutes. In my field, educational K12 we have maintenance Windows that run after school and district hours to avoid as much interruption to learning as possible. If I was to do the updates the manual method I would have had to start at 4:30pm on a Friday for 3 hours. While that would have been overtime, I would rather not stay after already working an eight hour day on a Friday if I don’t have to.
The Power of PowerShell made it so that my total time invested in the actual update was less than 10 minutes which includes the four the script took. The hour of writing and testing the script was during my normal work day so they don’t count. Because school is out, I was able to get the school based technology support personnel to agree to not be using the servers to let me start at 4pm instead of 4:30pm at the end of our day.
That means I was able to update a major tool of our classroom learning and IT software management during the work day in 4 minutes without any real disruption to anyone. Now that is what I consider good time management.
Overall, I saved the district 3 hours of overtime. At the same time I saved myself from an extra 3 hours at work on top of the eight I was already working and I was able to use them with my family. I also now have a script that I can use with a multitude of software installs to save even more time. That’s the Power of PowerShell.
Before I close I want to address the people that say I’ve hurt my value, made something that can replace me, or left pay in the bosses pockets. Well, to me those thoughts are from people who are insecure with themselves and are only looking out for themselves. I helped my value by making something that lets me spend more time on a different project that will help the students who I’m working for. I’ve also saved the district money that can be spent somewhere else that will help the students who I’m working for. We have a job not because of ourselves, but because of the end user. PowerShell makes that possible for me.