Posts related to PowerShell or scripting

Get-Command aka Discovering PowerShell

What’s the PowerShell command for…?” This happens to all of us. We’re working on a task and hit that speedbump where we either have forgotten or just don’t know the command to do that thing. This is where it’s very easy to turn to Google or Bing and and start searching. There is an easier way!

Really the issue with search engine results is that they may be incomplete, for a different version of PowerShell, or you just can’t find the answer. Whether it’s not using the right keywords, date constrictions, or whatever, the better way is right in front of you.

You have a PowerShell window open right? That’s why you are looking for commands right? Try this:


That’s nice, but on my machine ( with a few modules installed, granted) I get over 6,500 commands that way!
That’s not helpful without some limiting parameters. I do assume that you have an idea about what you are trying to accomplish. This is where the -noun and -verb parameters come in handy.

Let’s take a random example to walk through: What is the command to determine what services are running on a computer?
Our plain English request has verbs and nouns and PowerShell commands have verbs and nouns.
With a little knowledge of PowerShell structure, it’s pretty easy to work through.

Quick refresh: PowerShell commands (cmdlets) are structured in a “Verb-Noun” syntax.
Of all the verbs in the English language, there are (at this writing) 100 approved verbs. You can see the list at Approved Verbs for PowerShell Commands. 

That’s a lot but we can narrow those down pretty quickly by remembering a few things – Common verbs are things like Add, Clear, Close, Copy, Enter, Exit, Find, Get, Hide etc. We recognize ‘Get’ from other things like  GET-COMMAND! ‘Find’ also looks attractive in this case, so let’s have a quick look at that.

PS> Get-command -verb find

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Find-Certificate                             xCertificate
Function        Find-Command                                       2.2.5      PowerShellGet
Function        Find-Command                                 PowerShellGet
Function        Find-DSCResource                                   2.2.5      PowerShellGet
Function        Find-DscResource                             PowerShellGet
Function        Find-IpamFreeAddress                         IpamServer
Function        Find-IpamFreeRange                           IpamServer
Function        Find-IpamFreeSubnet                          IpamServer
Function        Find-Module                                        2.2.5      PowerShellGet
Function        Find-Module                                  PowerShellGet
Function        Find-NetIPsecRule                            NetSecurity
Function        Find-NetRoute                                NetTCPIP
Function        Find-RoleCapability                                2.2.5      PowerShellGet
Function        Find-RoleCapability                          PowerShellGet
Function        Find-Script                                        2.2.5      PowerShellGet
Function        Find-Script                                  PowerShellGet
Cmdlet          Find-Package                                       1.4.7      PackageManagement
Cmdlet          Find-PackageProvider                               1.4.7      PackageManagement

Ok that’s better but none of those seem to have anything to do with services. Let’s come at it from the ‘service’ side. You can list all the command with a certain noun or noun part using the -noun parameter.

PS> get-command -noun service

CommandType     Name                                     Version    Source
-----------     ----                                     -------    ------
Cmdlet          Get-Service                        Microsoft.PowerShell.Management
Cmdlet          New-Service                        Microsoft.PowerShell.Management
Cmdlet          Remove-Service                     Microsoft.PowerShell.Management
Cmdlet          Restart-Service                    Microsoft.PowerShell.Management
Cmdlet          Resume-Service                     Microsoft.PowerShell.Management
Cmdlet          Set-Service                        Microsoft.PowerShell.Management
Cmdlet          Start-Service                      Microsoft.PowerShell.Management
Cmdlet          Stop-Service                       Microsoft.PowerShell.Management
Cmdlet          Suspend-Service                    Microsoft.PowerShell.Management

Aha! That first one Get-Service looks good! Let’s try that one.

PS> Get-Service

Status   Name               DisplayName
------   ----               -----------
Running  AarSvc_11d5ae      Agent Activation Runtime_11d5ae
Running  AdobeARMservice    Adobe Acrobat Update Service
Running  AdobeUpdateService AdobeUpdateService
Running  AGMService         Adobe Genuine Monitor Service
Running  AGSService         Adobe Genuine Software Integrity Serv…

Bingo! Of course I abbreviated that list. There are 299 services on this machine right now. Perhaps we should filter that down a bit. Parameters are a good way to do just that. You can find the parameters using the Get-Help cmdlet.

PS> get-help get-service


    Get-Service [[-Name] <string[]>] [-DependentServices] [-RequiredServices]
    [-Include <string[]>] [-Exclude <string[]>] [<CommonParameters>]

    Get-Service -DisplayName <string[]> [-DependentServices]
    [-RequiredServices] [-Include <string[]>] [-Exclude <string[]>]

    Get-Service [-DependentServices] [-RequiredServices] [-Include
    <string[]>] [-Exclude <string[]>] [-InputObject <ServiceController[]>]


Let’s say that the service we are interested in is something to do with printers. We can use wildcards in the -DisplayName parameter to narrow this down

PS > Get-Service -DisplayName *print*

Status   Name               DisplayName
------   ----               -----------
Running  DLPWD              Dell Printer Status Watcher
Running  DLSDB              Dell Printer Status Database
Stopped  PrintNotify        Printer Extensions and Notifications
Stopped  PrintWorkflowUser… PrintWorkflow_11d5ae
Running  Spooler            Print Spooler

Of course you can use the PowerShell pipeline to do Where-Object filtering, start/stop/restart the services discovered, but all of that is another story for another time!

Powershell Tuesday Quick Tip #7

Back at it again!

This tip is a little snippet of code for building Dynamic distribution lists for something other than Organizational Units or Branch offices or the other examples. This one is to build a list of Managers.

How does one differentiate managers in Active Directory? Title? no because at least in our organization, the management team have different titles. Things like ‘Vice President’, ‘Director’,or ‘Controller’ in addition to the more mundane ‘Manager’. This is complicated by the fact that we refer to our outside salesforce as ‘Territory Managers’. So the Title property is right out.

What is the one other property that defines a member of a leadership/management team? Yep – they have someone reporting to them. Enter the “Direct Reports” property!

Team that up with a New-DynamicDistributionGroup Cmdlet and you get a new example like this:

New-DynamicDistributionGroup -DisplayName 'My Company Managers' `
 -Name MCManagers `
 -PrimarySmtpAddress 'mcmanagers@mycompany.com' `
 -RecipientFilter { DirectReports -ne $null}

*Standard disclaimer about minding the backtick line continuations. This is actually a one liner but considering the important part is at the end, this format is easier to read.

The result is a list of anyone in your organization that has someone reporting to them. Exactly what the HR folks want when they ask for a mailing list of all the managers!

Convert DHCP Lease to Reservation with Powershell

Scenario :  You have just created (by whatever means) a new server. It has gotten an IP address from DHCP and all is working as it should…..However…. Perhaps this server provides a service that requires a static IP (for whatever reason).

In the old days, you would fire up the DHCP tool from the RSAT tools or <shudder> RDP into your domain controller to convert the dynamic DHCP Lease into a reservation. There is a faster way…… if you guessed Powershell – you are correct 🙂

It took a little spelunking around to work this out but here are the steps to follow.

First, create a remote powershell session to your DHCP server.

 Enter-PSSession -ComputerName MyDC.houndtech.pri 

Next find out the IP address  of the new server. Easy enough with :

Test-NetConnection -computername Newserver.houndtech.pri 

Let’s make things a little easier for later and put that returned object in a variable.

$x = Test-NetConnection -computername Newserver.houndtech.pri  

But we don’t need the whole object, just the IP address, so let’s narrow it down with

$IP = $x.BasicNameResolution.IPaddress  

Now $IP contains JUST the IP address, which is what we need for the next series of cmdlets.
Next we retrieve the DHCP lease object with

 Get-DHCPServerV4Lease -IPAddress $IP 

Finally pipe it to the cmdlet to add the reservation.

 Get-DHCPServerV4Lease -IPAddress $IP | Add-DHCPServerV4Reservation 

Of course this could be piped together into a sweet oneliner that would go well added to any automated provisioning script.

 Get-DHCPServerV4Lease -IPAddress ((Test-NetConnection -ComputerName 'NewServer.HoundTech.pri').RemoteAddress.IPAddressToString)| Add-DhcpServerv4Reservation 

See you next time!

Powershell and Devops Summit 2018

Last week was the big Powershell/Devops Summit in Bellevue, WA. I say “big” not as in ginormous 15,000 attendee extravaganzas like Ignite or VMWorld. No, this 365 attendee Summit was big as in the stature of the people there. All the Powershell superstars were there, sharing their knowledge and enthusiastically pushing the rest of us to excel.

This was my first Summit, and although I have waded into the Powershell Community pool, this was a dive into the deep end! Happily, I managed to keep up and learn quite a few things that I can immediately apply. I also brought back copious notes on things to try out in the old Lab.

It would be a novella to describe all the things I learned, but here are a few highlights and key takeaways.

  • Powershell 6.x is the way forward. Cross-platform and lightweight, it will run on almost anything. There was a demo of a Raspberry Pi with Powershell 6 installed and sending sensor information ( heat – humidity sensor) and controlling an attached light. Pretty nifty. Also Cloud Shell (Azure Powershell in a browser) either runs now or will soon run v6.
  • To utilize old modules, soon to be released: Windows Powershell Compatibility Pack. This is a clever solution. It allows you to essentially remote into your own PC’s Windows Powershell (5.1) session. It’s a little confusing until you remember that Powershell 6 and Powershell 5.1 are different executables and can and do run side by side.
  • Powershell Classes + REST API’s = Super functions. In a nutshell, use  classes to build objects out of data returned from Get-RestMethod. Once it’s a fully fleshed out PSObject, you have many more options on how to interact with that data. Powershell is all about objects afterall. For more info: Tweet to: Jeremy Murrah or check out his presentation on GitHub
  • Desired State Configuration Pull Server is becoming more of a community/open source project. It appears (and maybe I misunderstood) that Microsoft isn’t doing much development on the Pull Server portion of DSC. They are focusing on the Local Configuration Manager (LCM). This makes a lot of sense, it’s easy and not expensive to use Azure Automation as your pull server. There are also a few other Open Source Pull servers like TUG
  • Lean Coffee! For a completely not  Powershell side session, Glenn Sarti introduced a few of us to ‘Lean Coffee’. It’s not a skinny half-caf soy latte, it’s a way to organize small informal meetings. Briefly, everyone gets Post-Notes ( or other slips of paper) and writes down 2-3 things they want the group to discuss at this meeting. Everyone votes on what they want to discuss and that determines the order of conversation. Someone acts as ‘timekeeper’, and every 2 minutes polls the group for a simple “thumbs up/down” vote. If the majority votes UP , the conversation stays on that topic, otherwise, you move on to the next highest voted topic. Repeat until time or topics runs out. I am definitely going to try this in our next team meeting! For more info – check out : http://agilecoffee.com/leancoffee/
  • I learned a LOT about CI/CD pipelines for Powershell using VSTS and a few other tools from both and in separate sessions. This topic needs a blog post or 6 all it’s own. Two things to remember – 1. it can start simple and build from there  and 2. Plaster frameworks make the dream work.
  • Thomas Rayner showed us how to make custom rules for PSScriptAnalyzer. Time to make some “house rules”!

There was a LOT more that I have noted to study up on and try out, those will be later posts I’m sure.

Of course, Jeffrey Snover  continues to amaze me with his enthusiasm and optimism. Some great ‘Snover-isms” heard: “Line noise should not compile!” and “Like cockroaches in a kitchen full of cowboys”.

Aside from actual sessions, there were several interesting conversations not only with superstars like Don Jones™ and Mark Minasi, but also with the “next-gen” stars like Michael Bender and James Petty and with regular Powershell guys like me.

As for the actual event, the folks that put this together are top-notch. They care about the experience we have and it shows. Very good food, opportunities to socialize, and a refreshing lack of hard sell vendors. One of the few conferences I go to that doesn’t result in an email flood in the week following.

Bellevue was great – it only rained 4 of the 5 days I was there! Seriously though, the rain wasn’t an issue – even though I walked everywhere except to and from the airport. A light misting drizzly rain wasn’t horrible, and the temperatures were great. Cool enough so that you could vigorously walk up hills without getting sweat soaked and warm enough that only a light jacket was needed.


Powershell Tuesday Quick Tip #6

This week’s tip is a bit longer – it’s actually a little script to remotely create a shortcut to a network file share on a user’s desktop. This one comes in handy when explaining how to make a shortcut over the phone proves …. difficult.

$PC = 'Luke-Laptop.rebellion.org'
$User = 'LSkywalker'
$TargetPath = "\\tactics.rebellion.org\death_star_plans\"
$ShortcutFile="\\$PC\C$\Users\$user\Desktop\Death Star.lnk"
$Obj = New-Object -COMObject Wscript.Shell
$Shortcut = $Obj.CreateShortcut($ShortcutFile)
$Shortcut.TargetPath = $TargetPath

This one is a good candidate for getting wrapped up in a function and added to an “Admin Toolkit Module”.

Powershell Tuesday Quick Tip #5

Here’s another one from the easy but annoying to rethink stack.
People, as someone once said, are ‘squishy and move around a lot’. Not only do they move but they change and sometimes the change involves their names.
For example, the customer service person gets married or the sales manager gets divorced.(Hopefully not for the same reason – but that’s a different blog)

So you can either fire up the Active Directory tool of your choice (ADAC or ADUC) OR switch over to your PowerShell console that you have open already.
… you DO have it open already right?

Set-AdUser -Identity Leia -Surname 'Solo' -DisplayName "Leia Solo"
Set-Mailbox -Identity Leia -PrimarySmtpAddress 'LeiaSolo@NewRepublic.gov' -EmailAddressPolicyEnabled:$False -DisplayName 'Leia Solo' -EmailAddresses @{add ='LeiaOrgana@NewRepublic.gov'}

The first line “Set-ADUser” changes Leia’s surname to Solo and corrects her display name. The second line, “Set-Mailbox” changes her primary email address to “LeiaSolo@NewRepublic.gov” along with her display name while adding her original email address back in as an alternate. This is so Leia will continue to get email from some people that haven’t gotten the happy news yet.

These two lines require that you have the Active Directory module and a remote session to either Office365 or your Exchange server.

Next week I’ll be blogging from the PowerShell + DevOps Global Summit in beautiful Bellevue WA!


Powershell Tuesday Quick Tip #4

I know, I know- stop using RDP to manage devices. The fact is some tech support issues are solved faster and easier if you just remote into the user’s PC. This is particularly true in a small business where perhaps GoToAssist and other such tools are not in the budget.

But what if the pc doesn’t have RDP enabled? Today’s tip fixes that on domain joined machines.
First let’s check…

$PC = "mycomputer.domain.com"
#Determine if Remote Desktop is enabled - 1= enabled 0= Disabled
Get-WmiObject -Namespace 'root\cimv2\TerminalServices' -Class Win32_TerminalServiceSetting -ComputerName $PC -Property allowtsconnections|
Format-List AllowTsConnections

Ok so it came back with a 0, let’s correct that.

$PC = "mycomputer.domain.com"
(Get-WmiObject -Namespace 'root\cimv2\TerminalServices' -Class Win32_TerminalServiceSetting -ComputerName $PC).setallowtsconnections(1)

And done!

Once you’ve finished, if you want, reverse the process with a value of (0) for setallowedtsconnections

Of course – if you CAN, it’s even faster an easier to fix things with Powershell remoting. Sadly, not every application is PSAware 😦

See you next week!

Powershell Tuesday Quick Tip #3

Printer Tricks

This week is a 2-for-Tuesday! Two basic printer tricks.
These come in really handy when troubleshooting the “I can’t print” help desk tickets. Like a lot of these types of one-liners, you have to be in the same domain as the target pc.

First, we can get the printer queue for a pc.

$pc ='Mycomputer.mydomain.com'
Get-WMIObject Win32_PerfFormattedData_Spooler_PrintQueue -ComputerName $pc|
Select-Object Name, @{Expression={$_.jobs};Label='CurrentJobs'}, TotalJobsPrinted, JobErrors

Secondly, there is this one to clear the printer queue

$PC = "mycomputer.mydomain.com"
get-wmiobject win32_printer -filter “Name='MyPrinterName'” -ComputerName $pc|
foreach {Write-verbose “Cancelling all jobs on $($_.Name)” $_.CancelAllJobs()}

*Note: For the “Clear Print Jobs” snip to work, you need to know what the printer is called on the target pc.

That one is handy for those times when someone has tried to print a poorly formatted file that puts the printer’s PCL logic into a tailspin. You can reboot everything but until you cancel that job, the printer will keep getting bogged down. It’s especially fun when you have 10+ people sharing a printer. This way you can wrap a “foreach” loop around the code and “Bob’s your uncle!”

Until next time!

Powershell Tuesday Quick Tip #2

This week is an easy one. Cleaning up Active Directory of old computers. Sometimes a machine gets retired or just completely craters and in the haste to get the user back up and going…. some clean up is forgotten. Easy to fix. this little snippet returns the time since PC has logged into the domain in DDD.HH:MM:SS format

$timespan = '90.00:00:00'
Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan $timespan|
Foreach-Object {Write-output $_.name} 

Of course it’s easy to add

 |Export-csv -Path C:\OLDPC.csv 

to the pipeline which gives you a CSV file to review and feed into a “Delete-OldComputer” oneliner!

See ya next week!

Powershell Tuesday Quick Tip #1

Let’s see how many Tuesdays I can do this!  The goal: a quick oneliner or at most 2-3 lines of code to do something timesaving and useful. For the Powershell gurus some may be simplistic but I can vouch that these all WORK as of spring of 2018. Which is more than you can say for some of the stuff that comes up for a Bing/Google (Bing-gle) search.

So today’s is something that came up today. I needed to change the mailbox/calendar settings on Rooms for meeting reservations in Outlook.

PROBLEM: By default, a Room mailbox only publishes meetings as “Busy” for any but the organizer.  So when other people really need that room, they don’t even know who to contact about maybe changing times around.


Get-Mailbox -Filter {(RecipientTypeDetails -eq "RoomMailbox")}|
ForEach-Object {Set-CalendarProcessing "$_" -AddOrganizerToSubject $True -DeleteComments $False -DeleteSubject $False}

Of course you have to be connected to Office 365 in your Powershell session first. Instructions on that are detailed here: Microsoft Docs 

See ya next week!