by David | Feb 13, 2021 | Information Technology, PowerShell
Do you need to audit your azure tenant for Licensed users vs non-licensed users? There is a simple way to do this using the MSOnline module. If you don’t have the MSOline module installed, you will need to install it. The big thing is this module only works on Powershell 5.1. So, let’s install and import our Module
Install-Module -Name MSOnline -Force
Import-Module MSOnline
Next step is to connect to the tenant. We do this with connect-msolservice. If you are doing this via the console, you can use the -Credential flag. if you are using this from a script, you will need to setup the PS credential object yourself. In this example, we are going to use the default console.
Connect-MsolService -Credential (Get-Credential)
Now we need to grab the users from the system. I want to grab all the users so we can audit accordingly. With the default Get-Msoluser you can select just the unlicensed users. You can even do the reconciled users. The way we get the all users is the -All flag.
$Users = Get-MsolUser -All
To gather the difference between the licenses and the non-licensesd we will use a where-object command.
$LicensedUsers = $Users | where-object {$_.islicensed -eq $true}
$UnLicensedUsers = $Users | where-object {$_.islicensed -eq $false}
Now we have a clear cut difference between the licensed and unlicensed users. We can continue to audit. If you just want the unlicensed users you can use the -UnlicensedUsersOnly flag.
$UnLicensedUsers = Get-MsolUser -UnlicensedUsersOnly
Unlicensed users can contain things like contacts and service accounts. So be careful. However, it does show users that might need to be given licenses. To filter out the contacts, all you have to do is remove the UserType Guest.
$NoContactUnLicensedUsers = $UnlicensedUsers | where-object {$_.UserType -ne "Guest"}
If you want to see the contacts, then you can just reverse this command and use the -eq instead of -ne.
$ContactUnLicensedUsers = $UnlicensedUsers | where-object {$_.UserType -eq "Guest"}
With the member only selected from the Unlicensed, you can review which ones needs the licenses and which ones do not.
Keep an look out, more azure auditing to come.
by David | Feb 1, 2021 | Help Desk, Information Technology, Resources
Here we are again, trying to make a device work from one center to another. Each center has the same server IP address but different subnets. All the subnets are /24. So, that makes life easier. All of them are .5 as well. So, that makes life much easier. So, how do we get a website started on .5 from every device but able to take it to another site? Well, the solution is simple. You find the IP address and tell the internet browser to start it for you.
First lets get the IP address and sort through it.
for /f "usebackq tokens=2 delims=:" %%f in (`ipconfig ^| findstr /c:"IPv4 Address"`) do set "ip=%%f"
The above is a loop for IP config to remove anything that is ipv6 to IPv four. Once we have our IPv4 Address we then loop through that and set each octet that we want to use.
for /f "tokens=1-4 delims=. " %%a in ("%ip%") do (
set octetA=%%a
set octetB=%%b
set octetC=%%c
set octetD=%%d
)
We sort through the IPv4 address and split each item via the . delimiter. Now we take that info and start our IE.
start "CMD" /D "C:\Windows\System32\" /max "C:\Program Files\Internet Explorer\iexplore.exe" "http://%octetA%.%octetB%.%octetC%.5/LocalWebsite/"
That’s it, a very simple process, but it can help with so much time.
The Script
@echo off
rem All i need to do now is grab only the IP address with batch.
rem ipconfig | find "IPv4"
for /f "usebackq tokens=2 delims=:" %%f in (`ipconfig ^| findstr /c:"IPv4 Address"`) do set "ip=%%f"
for /f "tokens=1-4 delims=. " %%a in ("%ip%") do (
set octetA=%%a
set octetB=%%b
set octetC=%%c
set octetD=%%d
)
start "CMD" /D "C:\Windows\System32\" /max "C:\Program Files\Internet Explorer\iexplore.exe" "http://%octetA%.%octetB%.%octetC%.5/LocalWebsite/"
exit
by David | Jan 14, 2021 | Information Technology, PowerShell
Do you need something to let your end-user know what’s going on? Don’t want your end-user to see the program running? Well, PowerShell has the ability to use the system windows notify system. AKA, the message box that pops up on the right of the screen.
The first step to make this happen is we need to add the assembly, system.windows.forms. We do this by the amazing command add-type.
add-Type -AssemblyName System.Windows.Forms
Now we have the assemblies loaded into ram, we need to create an object from those assemblies. This way we can command the object later. We do this using the New-object cmdlet. We want the notification tray icons. So we want the system.windows.forms.notifyicon.
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
You know that notifications have icons. Yep, It’s from the application itself. So, if you have this function in another application, it will show that the application’s icon. We call upon the System.Drawing.Icon to do this. But First, we need to know which app we are currently using. We do this with Get-Process with the ID and the current Pid.
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
What’s cool about this is we are extracting the icon of the application itself with that extract associated icon. We push it into our notify icon object. Next, we want to add the Tip Icon. That’s the ! ? so on and so forth. We do this by using the system.windows.forms.tooltipicon function. Believe it or not, we can use a validate set in the parameters to get the exact naming input as well. The property of the object is BalloonTipIcon.
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::$Messagetype
Now the message itself. At this point we have an icon, the notification icon and that’s it. This is the meat of the notification. The propriety in the balloon object is, BalloonTipText.
$balloon.BalloonTipText = $Message
Just a quick note, to much text is ugly.
Next is the title, I like to use just the word attention as it brings the users eyes to it. The balloon’s propriety for this is BalloonTipTitle.
$balloon.BalloonTipTitle = "Attention"
Finally, we want to make this thing visible. An invisible tooltip is as useful as invisible ink without a black light. As you have guessed by now, Visible is the balloon’s propriety.
Now the drum roll, please! It’s time to show our masterpiece that will be enjoyed by the end-user for a split second. The ShowBalloonTip(). Yes, let us do it! This is a method and will show the balloon tip for x time. This is set up in milliseconds. So, every 1000 milliseconds makes a second.
$balloon.ShowBalloonTip($Time)
Lets put it all together shall we. Behold the script of the balloon tip.
The Script
Function Invoke-SHDBallonTip {
[cmdletbinding()]
param (
[string]$Message = "Your task is finished",
[int]$Time = 10000,
[validateset("Info", "Warning", "Error")][string]$Messagetype = "Info"
)
#Adds the reqruired assembly's for the ballon tips.
Add-Type -AssemblyName System.Windows.Forms
#Creates the notifiy icon that will appear in the notification tray.
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::$Messagetype
$balloon.BalloonTipText = $Message
$balloon.BalloonTipTitle = "Attention"
$balloon.Visible = $true
$balloon.ShowBalloonTip($Time)
}
That’s it, folks. Such a simple thing. Here are a few things you can do. You can change the $path to $Path = Get-Process -id $PID. Then in the balloon.icon, use $path.path. In the balloon tip title, you can put $path.description and now you have the description as the title. Other than that, it’s pretty straight forward.
I would love to hear back from yall. Let me know if there is anything you would like for me to write about.
by David | Jan 7, 2021 | Information Technology, PowerShell, Resources
This will seem dumb, but do you need a message box in your script? Normally no, but when you are using a script for an end-user, you might need it. So, let us take a look at how to do it real quick.
The Script
function Invoke-SHDMessageBox {
[cmdletbinding()]
param (
[Parameter(HelpMessage = "Message Title", Mandatory = $true)][Alias('Title', 'header')][string]$MessageTitle,
[Parameter(HelpMessage = "Message Body", Mandatory = $true)][Alias('Boby', 'Information')][string]$MessageBody,
[Parameter(HelpMessage = "Message Buttons", Mandatory = $true)][Alias('Buttons')][validateset("YesNo", "YesNoCancel", "OK", "OKCancel")][string]$MessageButtons,
[Parameter(HelpMessage = "Message Image", Mandatory = $true)][Alias('Image')][validateset("Asterisk", "Error", "Exclamation", "Hand", "Information", "None", "Question", "Stop", "Warning")][string]$Messagetype
)
Add-Type -AssemblyName PresentationCore, PresentationFramework
$ButtonType = [System.Windows.MessageBoxButton]::$MessageButtons
$MessageIcon = [System.Windows.MessageBoxImage]::$Messagetype
$Results = [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $messageicon)
Return $Results
}
The Breakdown
Lets break this guy down. First thing first, the parameters.
- MessageTitle – What will be presented as the title of the message box.
- MessageBody – The message itself.
- MessageButtons – What types of buttons.
- YesNo
- YesNoCancel
- OK
- OKCancel
- MessageType – The type of image will be presented.
All the parameters are mandatory. None can be passed by the pipeline. All are single strings instead of my normal list of strings. It’s far easier that way.
Next, we need to add the assembly for the box. These are PresentationCore and PresentationFramework.
Add-Type -AssemblyName PresentationCore, PresentationFramework
Next, we just add items to the variables we will be using. The input from the parameters and their validate set. For the buttons themselves we call upon the power of the assembly we added earlier. [System.Windows.*] In the button case, the * becomes MessageBoxButton.
$ButtonType = [System.Windows.MessageBoxButton]::$MessageButtons
Then the message box image will be the same way, but with messageboximage.
$MessageIcon = [System.Windows.MessageBoxImage]::$Messagetype
Then we put it all together with the messagebox itself.
$Results = [System.Windows.MessageBox]::Show($MessageBody, $MessageTitle, $ButtonType, $messageicon)
The first part of the show is the body followed by the title, then followed by the buttons, and finally the image. Notice I pipe it into Results. I do this because we want to return those results.
That’s it! Once you return the results, you can test them with an if statement. Come back Monday for a ballon notification function.
by David | Jan 4, 2021 | Information Technology, PowerShell, Resources
Recently I came into a company where their printers were called printer 1, printer 2… and so on and so forth. It was amazing. No one knew which printer went where, and I was asked to make some kind of sense of it. Since I had the support of the people, why not print to all the printers with the printer names. Powershell can do this for you.
First thing first, you will need access to the print server to run this script from. The server will need PowerShell 5.1 or higher.
The Power of this script comes into play with Out-Printer. You will need the printer’s name and a message for that printer. Believe it or not, you can send multiple lines as a message too. Thus, you can create a nice message to print out. The next piece you will need is the Get-Printer command. The below script is a message I printed out at the company. It printed to every printer. of course, I had small trouble with non-physical machines.
Scripts
$Printers = get-Printer
foreach ($Printer in $Printers) {
$Message = @"
Hello, I am trying to assign printers to computers. I need some information. Please read over this and send the results to <your Email Address>.
1) Your name.
2) Your Computer name.
3) Your username, What you use to log into the computer with.
4) This Printers name: $($Printer.name)
To find your computer name follow these instructions:
1) Right-Click the start menu.
2) Click system
3) under "Device Specifications" you will find the device name. Note that name and add it to the reply email.
your email should look like the one below:
My Name: <Your Name>
Computername: <Your Computer name>
Username: <Your UserName>
Printer: $($Printer.name)
Thank you for your time in this matter.
"@
Out-Printer -Name "$($Printer.name)" -InputObject $Message
}
The Break Down
First we grab the printers with the Get-Printer Command.
Then we loop through the printers with a foreach loop. Inside that loop, we will do our work.
foreach ($Printer in $Printers) {}
Next, we create the message we want to print to each printer. We do this by doing a simple variable with what is called a here-string. Here-Strings are large strings that can contain special characters and much more. Oftentimes it’s Contained within @” some data “@. Notice that the $ still triggers variables, and you can still pull items out of variables by using the $($Var.info) options.
$Message = @"
Hello, I am trying to assign printers to computers. I need some information. Please read over this and send the results to <your Email Address>.
1) Your name.
2) Your Computer name.
3) Your username, What you use to log into the computer with.
4) This Printers name: $($Printer.name)
To find your computer name follow these instructions:
1) Right-Click the start menu.
2) Click system
3) under "Device Specifications" you will find the device name. Note that name and add it to the reply email.
your email should look like the one below:
My Name: <Your Name>
Computername: <Your Computer name>
Username: <Your UserName>
Printer: $($Printer.name)
Thank you for your time in this matter.
"@
Finally we push the information into the Out-Printer command. You will need the name of the printer you wish to print to and the message you want to print.
Out-Printer -Name "$($Printer.name)" -InputObject $Message
That’s it, nothing really much else after that. I hope you all can put this to good use.
by David | Dec 23, 2020 | Information Technology, PowerShell
Today, I needed to convert a mac address to a CIDR. The lesson I learned about this is to go back to the basics instead of looking around for a quick answer. So, to the basics first.
A mac address is a 4 octet number that represents a binary position. It ranges between 1 and 255. This means something like 255.255.255.0 is represented in binary as: 1111 1111 1111 1111 1111 1111 0000 0000
It’s easier to remember the 255 number instead of all those ones and zeros. However, what’s that CIDR? Well, what’s a CIDR? A CIDR represents the mac address and how many positions there are. If you count the number above, it turns into 24 1s and 8 0s. Thus the CIDR is 24. Very simple.
Now, how do you change 240.0.0.0 to a cidr? You can go to a chart and look or we can use PowerShell. The first thing we need to do is split up this string.
We split the string up with a split command and tell it to split it up by the . item. We use an exit \ because the . is a special character for regex. Next, we loop through this list of octets with a foreach-object loop.
$Mask -split '\.' | ForEach-Object {
}
Then we break down each octet into a binary number. We do this with a system.convert and tell it the number we bytes we want which is 2.
[System.Convert]::ToString($_, 2)
We then pad that information because sometimes 0s will produce more useless items.
([System.Convert]::ToString($_, 2).PadLeft(8, '0'))
The code above will give us the 1s and 0s of the binary number. Now we need to count the ones. We do this by converting the string to a char array with at .toochararray(). We search the string with a where-object for the number 1 and finally count it.
(([System.Convert]::ToString($_, 2).PadLeft(8, '0')).tochararray() | where-object { $_ -eq '1' } | measure-object).count
Now we need to add each item up. We do this by adding a variable before the loop set to 0 and then add the variable to the variable and the count. Finally, after the loop, display the information.
$Cidr = 0
$Mask -split '\.' | ForEach-Object {
$Cidr = $Cidr + (([System.Convert]::ToString($_, 2).PadLeft(8, '0')).tochararray() | where-object { $_ -eq '1' } | measure-object).count
}
$Cidr
That’s it yall! We count the number of 1s. That will give us our cidr count.
Script
Have fun with the script!
function ConvertFrom-SHDIPv4MaskToCidr {
param (
[string]$Mask
)
$Cidr = 0
$Mask -split '\.' | ForEach-Object {
$Cidr = $Cidr + (([System.Convert]::ToString($_, 2).PadLeft(8, '0')).tochararray() | where-object { $_ -eq '1' } | measure-object).count
}
$Cidr
}