Saturday, February 4, 2023

Finding Installed Applications (Get-ItemProperty vs. Get-WMIObject)

 Greetings everyone!

Forgive my absence.  I am working on my AZ-900 certification and there is a lot to learn!

This week I was given a list of servers.  I was tasked with getting all the applications installed on each of those servers.  So, I donned my PowerShell battle armor and faced the challenge.

First, I used the following code:
get-itemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-object DisplayName, DisplayVersion, Publisher, InstallDate | FT -AutoSize

This did give me a list of applications that had an Uninstall registry entry.  However, I know there were other programs that were not on the list.  So, I decided to use the following code:
Get-WmiObject -Class Win32_Product | Select-object Name | FT -AutoSize

It did give me more applications than the get-itemProperty code, but it took a lot longer for the list to appear.  The Get-itemProperty took 65 milliseconds.  The Get-WmiObject took 1 minute 22 seconds.

One article said to use Get-CIMInstance instead of Get-WmiObject in order to get a quicker response.  Get-CIMInstance took 1 minute and 37 seconds.  Oh, well.

I am still looking for a reason why the itemProperty command runs faster than the WmiObject command.  But, my main point is that there are two different ways to list what is installed on a computer, and that Get-WmiObject lists more installed apps than the other command.

As always, post a comment if you have any questions, or if you know why one is faster than the other.  I would appreciate it.  😀

Until next time...

Monday, January 16, 2023

Reviewing the Fundamentals

 Greetings everyone!

I haven't posted in a while due to the holidays, the flu, and taking some much needed time off.  But, I am back and I want to talk about how, sometimes, revisiting the fundamentals is beneficial.

I downloaded Jeff Hicks' "The PowerShell Practice Primer" (https://leanpub.com/psprimer).  For $29.95, it is well worth the spend.  Why?  Well, let me tell ya...

As you all know, I love PowerShell!  It has saved me a lot of time and headache, especially when managing Active Directory.  So, I want to keep my skills sharp and I thought Jeff's book would do that for me.  The exercises in the book showed me that I often overthink a solution to a problem.  For example, Exercise 11 asks you to get all of the 'get' commands in the PSReadLine module.  This was something I didn't know how to do.  After fumbling with some of the cmdlets, I looked at the solutions and found the following:
Get-Command -module PSReadLine -Verb get

Another example, I am used to putting output into a variable and then doing a ForEach loop to get the information I need.   Exercise 19 asks to create an XML file for all processes running under my account name.  My solution was:

$processes = get-process -IncludeUserName
$me_process = Foreach ($process in $processes)
{
  If ($process.UserName -like "*me*")
  {
    $process.ProcessName;$process.UserName
  } 
}
$me_process | Export-Clixml C:\users\trekr\documents\exer19.xml 

As you can see, I used a variable and a ForEach loop...not efficient what so ever.

The solution was much simpler:

Get-Process -IncludeUserName | where-object {$_.Username -eq "$($env:USERDOMAIN)\$($env:USERNAME)" } | Export-Clixml -Path myprocs.xml

Pipelines make things simpler.  I had forgotten that.

We should be creating efficient code.  Which is why I decided to practice my skills.  I feel that people who script, no matter their experience, benefit from stepping back and examining their coding style.  Any little change may be what is needed to improving their coding.

I would be interested in your opinion on this.  So, please feel free to comment.

Until next time...

NOTE: Jeff Hicks gave me permission to use the examples from his book.  He's a good guy.

Monday, December 19, 2022

Finding Mailbox With a Specific Proxy Address

 Hello everyone!

I recently got a request to find a mailbox that is using a specific proxy address.  I have been working for my company for over 3 years and I found it interesting we haven't been ask to do this sooner.  It is requests like this that shows the usefulness of PowerShell.

The first script that was created just checked Active Directory for the proxy address:
Get-ADUser -Filter * -Properties proxyaddresses | Select -Object Name,@{L="ProxyAddresses";E={($_.ProxyAddresses -match '^smtp:')}} | fl

You will get the following output:





Since I believe in the concept of "complete work", I changed the script to search Exchange Online for the proxy addresses.  Connect to MSOL and use the following:
Get-MSOLUser -all | Select-Object UserPrincipalName,,@{L="ProxyAddresses";E={($_.ProxyAddresses -match '^smtp:')}} | fl

This will give you the same output format as the first script.

For both scripts, you can substitute "-match '^smtp:'" for something more specific.  For example, if you want to search for proxy addresses that start with "HR', you can change the script as follows:
Select-object Name,@{L="ProxyAddresses";E={($_.ProxyAddress -match '^smtp:hr*')}}I

As always, I hope you found this information useful.  Please feel free to post a comment or question.

Until next time...


Sunday, December 11, 2022

Pulling list of Azure servers

 Greetings everyone!

Sorry for the delay but I had either a cold, the flu, or, possibly, the plague.  But I am back with another terrific script from my good friend, Ross Jurek.

Ross created a script that will gather all Azure subscriptions, based on your Azure account, and list the virtual machines for each subscription.  The following information is retrieved:
Name
OS
Location
The state of the VM

Here is the script:

Connect-AzAccount -Verbose -Tenant <your tenant ID> 

$VMReport = @()
#Get All Subscriptions
$subs = Get-AzSubscription 
#Arry to store list of VMs
$vmobjs = @()
#loop through each subscription

foreach ($sub in $subs)
{
#Display the current processing subscription
Write-Host "Processing subscription $($sub.Name)"
    try
    {
    #Select the subscription
    #please add the condition if you want to skip a particular subscription

    Select-AzSubscription -SubscriptionId $sub.SubscriptionId -ErrorAction Continue

    #Get all the VMs information
    $vms = Get-AzVm 

     #loop through all the VMs
        foreach ($vm in $vms)
        {
            $PowerState = Get-AzVM  -Name $vm.Name -Status | select-object PowerState
            $vm.Name , $vm.StorageProfile.OsDisk.OsType , $vm.Location , $PowerState.PowerState
            $VMReport += New-Object psobject -Property @{
            "VMName" = $vm.Name
            "VMOSType" = $vm.StorageProfile.OsDisk.OsType
            "VMLocation" = $vm.Location
            "VMState" = $PowerState.PowerState
            }
        }
    }
    catch
    {
        Write-Host $error[0]
    }

}

#export to csv format
Remove-Item c:\temp\AzureServerList.csv -ErrorAction Ignore
$VMReport | Export-Csv "c:\temp\AzureServerList.csv"

Disconnect-AzAccount

I have a Virtual Studio subscription and I didn't want that information to be part of the output.  I made the following change to the $subs = Get-AzSubscription command
$subs = Get-AzSubscription | where-object { $_.Name -like "My Cloud*"}

I had an issue when I first tried the script.  I kept getting the following message for each VM:
WARNING: There are more than 100 VMs in the result.  Only the statuses of 100 VMs are shown to avoid throttling.  To get the actual status of each VM, please provide a VM name with -Status parameter.

I talked with Ross about this and he recommended I either install or upgrade my Az module.  So, if you get the error, try either of the following:
install-module -name Az -RequiredVersion 9.1.1
update-module -name Az -RequiredVersion 9.1.1

Again, I want to thank Ross Jurek for sharing this code with us.

Please leave a comment if you have any questions feedback.

Until next time...

Sunday, November 27, 2022

Update on the MIM Script from Last Post

On PowerShell Power Users LinkedIn group, Tim Clapper posted a way to speed up the main script.  Here two snippets from the the script I posted:

$results = get-aduser -filter * -properties * | where-object {$_.givenName -eq $FirstName -and $_.sn -like $tempLastName| select-object givenname,sn | Measure-object

While ($results.count -eq 1

#this checks if there is an account with the first name and last name.  If $results.count is zero, the while loop is exited.

{

       $tempLastName = $LastName + $counter

       #This command now looks for a first name and last name+counter.

       $results = get-aduser -filter * -properties * | where-object {$_.givenName -eq $FirstName -and $_.sn -like $tempLastName| select-object givenName,sn | measure-object

       $counter++

}

Tim recommended I make the following changes to speed up the script:
1. Instead of using the where-object statement, move the conditions to the -filter switch
2. Instead of using 'sn', use 'surname'

The changes would look like the following:

$results = get-aduser -filter(givenName -eq $FirstName -and surname -like $tempLastName) | select-object givenName,surname | measure-object

Within the While loop

While ($results.count -eq 1

#this checks if there is an account with the first name and last name.  If $results.count is zero, the while loop is exited.

{

       $tempLastName = $LastName + $counter

       #This command now looks for a first name and last name+counter.

       $results = get-aduser -filter(givenName -eq $FirstName -and surname -like $tempLastName) | select-object givenName,surname | measure-object


       $counter++

}


I've tested the code and it does run faster since the code isn't searching all of Active Directory with the Where-Object command.

Test the change for yourself and let me know what you think. You can find the full code and MIM activity screen shot at https://github.com/mikeegan400/MIM-Test-for-Unique-First-and-Last-Name

A huge thank you to Tim Clapper.  He is one of the many PowerShell fans in the LinkedIn PowerShell group.  I highly recommend you join!

Until next time...


Monday, November 21, 2022

Triumphant Return and a MIM Script

 I'M BACK!!  It has been way too long but I am back.

I will be posting more scripts that we create and use in the company I work for.  They will be mostly GET- scripts against Active Directory, as well as the PowerShell commands we use in our Microsoft Identity Management (MIM) environment.

So, let's get started with a MIM script that we use to look for unique first name and last name within the MIM portal.

As you may or may not know, the MIM portal has PowerShell version 2.0 embedded in the portal.  In order to use the get-ADuser, you need to be running PowerShell version 3.0. I was able to find a workaround so that the main script can be executed using PowerShell 3.0.

I created two scripts, the main scripts and the script that runs inside the activity.

This is the code that is running within the PowerShell activity:

 As you can see, the command that starts with $templastname runs the PowerShell command but it runs it under version 3.0.  This was how I was able to work around the PowerShell 2.0 limit within the MIM portal.

PARAM(

[parameter(mandatory=$true)]$FirstName

,[parameter(mandatory=$true)]$LastName

)

$tempLastName = powershell -version 3.0 -command "c:\scripts\test_unique_lastname.ps1 $firstName $lastname"

$tempLastName


This is the main script.

#This makes the variables available to the script.

PARAM(

[parameter(mandatory=$true)]$FirstName

,[parameter(mandatory=$true)]$LastName

)

#This loads the module in case it isn’t already loaded

import-module activedirectory

#This sets the counter for

[int]$counter = 2

$tempLastName = $LastName

#This command looks for an account that contains the first name and last name similar to what was entered in the portal

$results = get-aduser -filter * -properties * | where-object {$_.givenName -eq $FirstName -and $_.sn -like $tempLastName} | select-object givenname,sn | Measure-object


While ($results.count -eq 1

#this checks if there is an account with the first name and last name.  If $results.count is zero, the while loop is exited.

{

       $tempLastName = $LastName + $counter

       #This command now looks for a first name and last name+counter.

       $results = get-aduser -filter * -properties * | where-object {$_.givenName -eq $FirstName -and $_.sn -like $tempLastName} | select-object givenName,sn | measure-object

       $counter++

}

#This value is returned to the PowerShell activity in the portal
$tempLastName

 

The scripts and the screenshots of the PowerShell activity are available in my GitHub account, https://github.com/mikeegan400/MIM-Test-for-Unique-First-and-Last-Name.  Please feel free to contact me if you have any questions or comments.


Monday, October 17, 2022

Long time, no see

 I have been doing a lot of PowerShell scripting in my current job.  The best part is that most of the team are PowerShell enthusiasts.  So, I am getting a lot of ideas and suggestions for new scripts...which I will share with you folks.

My plan is to post one day a week.  The topics will vary from cool scripts to resources to helpful tips.

I am excited to get back to this blog.  I hope you will all find it helpful.


Until next time,
Mike