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
}
by David | Dec 6, 2020 | PowerShell
Need 1000 or unique user photos for your lab? There is a great website for just such a thing. https://thispersondoesnotexist.com/image. Let’s break down some code to see how we can pull a few hundred pictures.
The first thing we need to know is how many we want. We are going to get 1000 faces for this example. Next, we need a safe location. Finally, we need an sleep time for the site to regenerate an image. Lets get started.
$StartCount..$FinishCount
the two . in this code allows you to loop through two values. Next we need to pipe this command into a foreach object loop.
$StartCount..$FinishCount | foreach-object {}
Inside the for each loop we start the real work. We are going to use the Invoke-WebRequest. Our URI is the site “https://thispersondoesnotexist.com/image” We will select where we want to save the file using the -outfile location. We are going to save it in the save location we choose earlier. We will put the name as the number you are currently using. Finally we will add a -disablekeepalive flag to stop the system from keeping the connection alive. We do this out of respect for the site.
Invoke-WebRequest -Uri $URL -OutFile "$SaveFolder\$_.jpg" -DisableKeepAlive
Next we need to do a sleep cycle. We do this because if we do a request after another request, we will get the same image. 7 Seconds seems to be the magic number. We do this with Start-Sleep -Seconds 7.
That’s it, It’s a simple process. The Invoke-WebRequest will get the needed image and save it to your computer. The site will generate a new picture each time you reach out.
The Scripts
Here is the script below.
function Get-Faces {
param (
[int]$StartCount = 1,
[int]$FinishCount = 1000,
[int]$SecondsToSleep = 7,
[string]$SaveFolder = "C:\Dpb\100000 Faces"
)
$URL = 'https://thispersondoesnotexist.com/image'
$StartCount..$FinishCount | foreach-object {
Invoke-WebRequest -Uri $URL -OutFile "$SaveFolder\$_.jpg" -DisableKeepAlive
Start-Sleep -Seconds $SecondsToSleep
}
}
Have fun with this little guy, just remember to be respectful of the sites you are pulling information from.
by David | Nov 22, 2020 | Help Desk, Information Technology, PowerShell
Do you have an admin account that needs to be hidden? Setting up this account among 2000 machines at different sites and different clients? Sounds like a nightmare right? Well, you can easily hide a user’s account from the login. This is done through the registry.
HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList
Inside here, we create a Dword with the username that we want to hide from the start menu and set it to 0 to hide the user and 1 to make it visible. So the code is a single liner. We create the Userlist, if it doesn’t exist, and make the new item property.
This code will make the user visable.
New-Item 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList' -Force | New-ItemProperty -Name $Param1 -Value 1 -PropertyType DWord -Force
This code will make the user hidden.
New-Item 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList' -Force | New-ItemProperty -Name $Param1 -Value 0 -PropertyType DWord -Force
Make sure to replace the Param1 with the username accordingly. After that you will need to reboot and should be good to go.