Good morning,

For a while now whenever I have needed to automate something, I’ve been able to find some script online to accomplish what I need. When they are well explained and commented, it is not too hard to tune them a “tiny” bit and be able to see that it will indeed do what it says (and not else).

I have started to read again “Learn Windows PowerShell in a month of lunches” which is a great book, but at this stage, I’m not learning anything I couldn’t do faster thru the GUI. This is what previously got me to stop, the sense of “this isn’t really useful to me right now”. Long term, it sure is but that is not how the human brain manages motivation, sadly!

I want it to be useful, but things like getting event logs and filtering them I can just do thru the GUI faster. Sure I could use PS to do it for the sake of it, and I might start doing just that.

I’m just wondering what your thoughts and recommendations are for IT people who haven’t used PowerShell much or at all to make it useful right away when you start to learn it.

Thanks!

8 Spice ups

To put it simply, PowerShell, like most other scripting and programming languages, is most useful for automating repetitive tasks. Some examples :

  1. Creating a number of new users from a csv
  2. Cleaning up drives
  3. Deploying/managing websites in IIS
  4. Software build pipelines

I’m currently building an organizational IIS Log Parser and Aggregator using primarily PowerShell. This will save us a bunch of time and money when it comes to generating reports on this data.

1 Spice up

I was in that same boat for years when I worked for a smaller company. What pushed me over to PowerShell was moving to a company with 25K+ computers and employees. When you have to make bulk changes or queries, PowerShell is the way to go. For example, we needed to change the UPN for all users for Office 365 purposes. I could open up Active Directory Users and Computers and edit each user. That would be tiring even for 30 people. Or I could do everyone with a line of PowerShell code. 25K people? You are not doing that by hand. Need a list of every user that doesn’t have a manager defined? PowerShell. Need to find out who has password never expires checked? PowerShell.

PowerShell profiles and functions are your friends. For example, I have a function in my profile to force an AD replication. I have one to force an Azure replication. Very handy when I need a change made immediately. The location I’m in happens to be where the PDC lives, so my changes get made there. Azure AD connect on the other hand syncs to a domain controller in a different site. So if I make a change, I can quickly force the AD replication followed by forcing an Azure replication. Find stuff like that you use daily, make a function for it, put it in your profile.

I have variations of Get-ADUser and Get-ADGroupMember that give me different output from the standard that I find useful. Sure I could type in what properties and select manually any time I need to do that, but this is a time saver. I have a command to set the Window Title. If you’re like me and you have several windows open at any given time, you might want to title them so you know which one is doing what.

Give you an example of some of my profile.ps1 (the xxxxxxx would be the Server names I’m calling it against, so for the AD sync, that’s the server with my PDCe role, and for the Azure sync it’s the server running Azure AD Connect and the user name is changed obviously). All of this stuff I could type in manually, but it’s a huge time saver just to make functions for it. I prefer to set the window title of my PowerShell window to know what user I’m running as (I have separate admin accounts for various things) and what particular thing I’m connect to, for example Azure or Exchange Online. You could obviously change the function names to suit whatever you like. Is “cad” formatted like a Verb-Noun PowerShell command? No. Do I care for my own use? Also no. Did I finally get with the program on that last function? Yes. Will I change the others at some point? Maybe. :slight_smile: Do I like that when I connect to Azure online PowerShell multiple times a week that it’s just 3 letters? Absolutely.

function Set-WindowTitle {
    Param(
        [parameter(Mandatory=$true)]
        [String]
        $Title 
        )
     $host.ui.RawUI.WindowTitle = $Title
}

function myGet-ADGroupMember {
    Param(
        [parameter(Mandatory=$true)]
        [String]
        $GroupName 
        )
     Get-ADGroupMember $GroupName | Get-ADUser -properties Mail | select SamAccountName, Name, Mail, Enabled, @{Name = 'OU';Expression = {$_.DistinguishedName -replace '^.*?,(..=.*)$', '$1'}}  | sort name
}

function myget-ADuser {
    Param(
        [parameter(Mandatory=$true)]
        [String]
        $User 
        )
    Get-ADUser $User -Properties LastLogonDate |select SamAccountName, Name, Enabled, LastLogonDate
}

#Connect to Exchange Online
function cexo {
    $host.ui.RawUI.WindowTitle = "365 Exchange Online PowerShell"
    Connect-ExchangeOnline -UserPrincipalName myuser@mydomain.com
}

#Connect to 365 compliance center
function ccomp {
    $host.ui.RawUI.WindowTitle = "365 Compliance Center PowerShell"
    Connect-IPPSSession -UserPrincipalName myuser@mydomain.com
}

#Connect to Azure AD
function cad {
    $host.ui.RawUI.WindowTitle = "Azure AD PowerShell"
    Connect-AzureAD -AccountId myuser@mydomain.com
}

#Force AD Replication sync
function SyncAD {
    Invoke-Command -ComputerName xxxxxxxxx {repadmin /syncall /AdeP}
}

#Force Azure Replication sync
function SyncAAD {
    Invoke-Command -ComputerName xxxxxxxx {Start-ADSyncSyncCycle -PolicyType Delta}
}

#Disconnect all PowerShell sessions
function dmso
{
    Get-PSSession | Remove-PSSession
}

#Clear DNS cache on all domain controllers
function Clear-AllDNSServerCache {
    foreach ($Server in (Get-ADDomainController -Filter *).name) {dnscmd $Server /clearcache}
}

$host.ui.RawUI.WindowTitle = "$env:ComputerName - $env:UserName Powershell"

5 Spice ups

I started very simple with finding and unlocking user accounts. Worked up to pulling specific user account information. I have a function that will randomly pull two words from a text document. Eventually I got to a point where I wrote a script to update our phone system software. It copied the install files to the local computer, checked for certain directories and installed only the updated programs that were installed and then deleted the install files. I know that this is minuscule as to what PowerShell can do but I am learning as I go. I am currently trying to write a script to create new users in AD from a current user.

1 Spice up

You may start to do that to get some more practice and get used to Powershell. More ideas will come.

@alkibiades ​, instead of looking for on or two events, you could try using it to parse through the logs to look for commonalities. You can achieve layers of complexity that you can’t do by simply looking at the Event Viewer. You can write a script to view security logs to see who is using what resources. You can write one that will tell you what server rebooted when and how long it took. You can track intermittent warnings, to see if there are signs of a failing NIC card. My first taste of Powershell scripting was to make a log scraper that would read from a folder audit to tell me who was accessing certain files (by extension type) and when, and outputting to .csv.

Or, you could try re-writing some of what you had already found online on your own. I understand the need for speed. But, sometimes, you have to force yourself to take the long road.

Or, try writing a script that will read the status of and, if necessary, update a free DDNS registry which you create at www.noip.com .

Usually, when I need/want to learn something new, I try to push a project that requires those kinds of skills to my management. If they approve it, I have no other choice or excuse not to do it, and a precise deadline which makes the learning effectiveness almost perfect :wink:

2 Spice ups

Once you get started down this slippery slope, it’s hard not to find uses for PowerShell.

One recent example, I needed to document some specific things about each computer in this LAN, so I made this:

<#
Get-AllOS.ps1
Create an output Object that will contain details about each OS in the AD, to be piped into whatever.

.\Get-AllOS | FT Computer, OS*, Uptime, "Logged-In User" -A
.\Get-AllOS | Export-Csv -NoTypeInformation -Force "Get-AllOS-($(Get-Date -format yyyy-MM-dd-HH-mm-ss)).csv"
#>
Write-Host "`t`t`t$(([io.fileinfo]$MyInvocation.MyCommand.Definition).BaseName) -- Gather OS Details about all PCs in the AD`n`n" -Fore Green

If ($Args[0]){$PCList = $Args.Split(',').Trim(' ')}  # Allow command-line input
Else {
	$PCList = (Read-Host "Enter Computer Name(s); ([Enter] for all)").split(',').trim(' ')  # Separate names with ',' no quotes, trim spaces
	If (!$PCList){$PCList = (Get-ADComputer -Filter {Enabled -ne $False} -Properties Name).Name}
     }
[Array]::Sort($PCList)
ForEach ($PC in $PCList){ 
	Write-Progress -Activity "Inventorying OSs" -Status "Checking $PC" -PercentComplete ($PCList.IndexOf($PC) * 100 / $PCList.Count) -CurrentOperation "$Status" -ID 0
	If (Test-Connection $PC -Count 1 -Quiet)  # Make sure it's online
	{
# Gather details
		$OS = Get-WmiObject Win32_OperatingSystem -ComputerName $PC -ErrorAction SilentlyContinue
		If ($OS){
			$UpTime = (Get-Date) -`
			 ([Management.ManagementDateTimeConverter]::ToDateTime($OS.LastBootUpTime))

			$Build = Switch -WildCard ($OS.Version){
				'*19044*'{"$($PC.Name) 21H2"}
				'*19043*'{"$($PC.Name) 21H1"}
				'*19042*'{"$($PC.Name) 20H2"}
				'*19041*'{"$($PC.Name) 2004"}
				'*18363*'{"$($PC.Name) 1909"}
				'*18362*'{"$($PC.Name) 1903"}
				'*17763*'{"$($PC.Name) 1809"}
				'*17134*'{"$($PC.Name) 1803"}
				'*16299*'{"$($PC.Name) 1709"}
				'*15063*'{"$($PC.Name) 1703"}
				'*14393*'{"$($PC.Name) 1607"}
				'*10586*'{"$($PC.Name) 1511"}
				'*10240*'{"$($PC.Name) 1507"}
				Default {" Old"}
				}  # End of Switch
			Write-Progress -Activity "$($OS.CSName + ' - ' + $OS.Description)" -Status "$(($OS.Caption + ' ' + $Build).Replace("`t"," "))" -ID 1

			Try {$User = (Get-WMIObject Win32_ComputerSystem -ComputerName $PC -ErrorAction Stop).UserName.split('\')[-1]}
			Catch {$User = "No one."}

			[PSCustomObject] @{
			   "Computer" = $OS.CSName + ' - ' + $OS.Description
			   "OS" = $OS.Caption + ' ' + $Build
			   "Service Pack" = $OS.CSDVersion
			   "OS Arch." = $OS.OSArchitecture
			   "Installed On" = [Management.ManagementDateTimeConverter]::ToDateTime($OS.InstallDate)
			   "Registered User" = $OS.RegisteredUser
			   "SerialNumber" = (Get-WmiObject SoftwareLIcensingService -ComputerName $OS.CSName).OA3xOriginalProductKey
			   "Boots From" = $OS.SystemDrive
			   "Windows Directory" = $OS.WindowsDirectory
			   "UpTime" = "{0:00} Days {1:00} Hrs {2:00} Min" -f $UpTime.Days,$UpTime.Hours,$UpTime.Minutes
			   "Logged-In User" = $User
			   "Notes" = $Notes
			}  # End PSCustomObject
		}  # End if OS available
	}  # End If it's online
}  # End For Each PC

This uses the “old school” way of taking command-line input, which is plenty since I mainly wanted a full network sweep; but with the option to examine a single PC.

I usually put my preferred invocation command in the heading comment box so I can just copypasta the whole command.

“See a need, fill a need.”

You know your job and what you do better than anyone. Look at what you do day in and day out and see can be automated. If you’re in a smaller organization it may be more difficult as you mentioned. Since most of your tasks are mostly a few clicks here and there, logging into server a and executing this or that, it may not be much help in that area. What if you are needing to change ABC on 2+ computers? Already have a script? 2 seconds. The second best choice if you’re use case may not be (at least initially) automation of tasks, look into reporting. That’s what I started with. Create a process that looks for user accounts in ad that have their password never to expire and email yourself a report. Get fancy and email the user and their manager (if you populate those fields in ad). C level staff LOVE reports!

1 Spice up

A user locked themselves out.
Launch AD, right click on the domain and find the user by typing their SAM in the find , double-click to bring up their properties, switch to the account tab, click to unlock their account
That’s 6 steps minimum plus typing.
vs.

Unlock-AdAccount SamAccountName

GUIs don’t scale!

If you have a process wherein you’re using GUIs to perform your administrative work, there’s a way to automate it and almost certainly via PowerShell.

I worked with an Admin who used to take screen-shots of the processes required for our administrative work.
He would write detailed instructions with pictures showing how things shall be done.

I would take his documents and write PowerShell to replace the various steps/processes.

I created scripts which can be run in seconds to replace what used to take 5 minutes each time we had to do the process.

2 Spice ups

There are lots of things within systems administration that require monotonous, repetitive GUI interactions unless automated and scripted. As soon as you notice yourself doing such a routine, please start thinking about how you can automate it.